test
[hcoop/zz_old/ikiwiki] / DomTool / UserGuide.mdwn
1 #pragma section-numbers off
2
3 This is the DomTool User Guide. The properties of DomTool are described, as well as its use and its configuration file format.
4
5 [[TableOfContents()]]
6
7 = Overview =
8
9 HCoop is almost unique in the history of the Internet. We are trying to provide highly configurable Internet hosting to the general public while maintaining a high level of security, so that your services keep running and your data stays safe and private. You can probably see that these goals conflict in a number of ways! Since our organization's birth in 2002, we've been evolving tools to help us reconcile these different goals. This document introduces the primary element of our current solution.
10
11 This solution is called DomTool, and here's the one-line summary of what it's all about:
12 DomTool enables HCoop members to use a '''domain-specific programming language''' to describe how to configure daemons spread across our servers.
13
14 Some other cogent properties of DomTool:
15 * The language is a '''[http://en.wikipedia.org/wiki/Statically_typed statically-typed], [http://en.wikipedia.org/wiki/Purely_functional purely functional] programming language'''. Other functional programming languages that you might have heard of include Lisp, Scheme, ML, and Haskell. Haskell and ML are statically-typed, and Haskell is purely functional.
16 * The language has a rich and extensible type system that can '''enforce complicated security policies through type-checking'''.
17 * Configuration works via a '''distributed client/server architecture''', so, with the right software installed, you can configure your domains from anywhere.
18
19 Some readers may be scared off by this level of technical jargon. We apologize, but we just couldn't help showing it off. ;-) The rest of this document will be aimed at the average member, assuming only a solid understanding of the basics of Linux and the Internet. In particular, we assume no experience with particular kinds of programming.
20
21 = Configuration files =
22
23 In this example, we'll assume that you've requested and been granted privileges to some Internet domain name (like `you.com`) via our [https://members2.hcoop.net/portal/domain domain permission request form]. If you ''don't'' want to configure a domain that you own, then you don't need to be using DomTool!
24
25 You will edit a text file with the configuration directives you want applied your domain. Where `$USER` is your HCoop username and `$DOMAIN` is your domain name, you should write configuration into a file `~$USER/.domtool/$DOMAIN`. If you're logged into one of our servers, `cd ~/.domtool` should get you to the proper directory. Otherwise, it can be useful to know that your home directory is something like `/afs/hcoop.net/user/u/us/username`, where you should replace `username` with your HCoop username and `u` and `us` with the one- and two-character prefixes of that username. Be sure that your `.domtool` directory has an AFS ACL set that allows the user `domtool` to read it, or your domains may go down when we need to reload everyone's configuration. If you end up with the wrong permissions, see MemberManual/GettingStarted/AfsExamples for the right command to run.
26
27 We leave it up to you to choose how to edit the source file. You might run something like `emacs $DOMAIN` over SSH, or you might open it locally if you have our AFS cell mounted in your local filesystem. In the latter case, those of you lucky enough to be using UNIX-based home systems will probably want to create softlinks from your local home directories to your HCoop home directories in AFS, to save some typing each time you want to open Domtool files.
28
29 In this file `$DOMAIN`, you can write:
30 {{{dom "$DOMAIN" with
31 end;}}}
32
33 You should replace `$DOMAIN` with the actual domain name. This example introduces the simplest useful configuration, based on the `dom` directive. What does this source file accomplish? It:
34 * Declares our nameservers as authoritative for your domain.
35 * Declares that Exim should handle e-mail for your domain.
36 * Directs Exim to send all mail to your domain to your mailbox.
37 * Adds a DNS mapping from `www.yourdomain.com` to our web server's IP address.
38 * Creates an Apache virtual host at that hostname serving `~$USER/public_html/`.
39
40 There are more primitive configuration directives to set up each of these features individually. `dom` packages all of the functionality together in an easy-to-use package. One of the main principles behind DomTool and our use of it is to '''avoid configuration repetition wherever possible'''. The DomTool language contains several abstraction features familiar from high-level programming languages, as well as some new ones, all in support of abstracting common code patterns into programming language entities that can be called multiple times. In general, if you find yourself writing the same code over and over again, let us know, and we'll try to add a new abstraction to our standard library! You could even write such an abstraction yourself, but that's beyond the scope of this intro document.
41
42 Now, enough talk; let's execute our source file! Assuming that you're in your `.domtool` directory, run{{{
43 domtool $DOMAIN}}}
44
45 This contacts our central dispatcher server over an SSL connection. Once the server verifies that you are who you say you are, it will publish your configuration to the affected daemons, and you should be able to start using your domain.
46
47 You could also simply run{{{
48 domtool}}}
49 which calls the dispatcher with '''all''' configuration files in your `.domtool` directory, regardless of what your current working directory is. This can be a helpful shortcut sometimes, though it can be noticeably less efficient than calling `domtool` with the single domain that you know you've changed.
50
51 In fact, the names of the source files in your `.domtool` directory don't matter. We recommend storing the configuration for each of your domains in a separate file named after that domain, but you might want to make different choices. For instance, you might want to use an abstraction that configures multiple domains at once. However, it '''is''' important that you keep all your permanent configuration files in your `.domtool` directory. Sometimes we need to reprocess all configuration from scratch, and in such cases our dispatcher will only look for source files in your `.domtool` directory. For temporary experimentation, though, you can feel free to store source files elsewhere and run them explicitly with `domtool $FILENAME`.
52
53 = Debugging configuration files =
54
55 To check a configuration file without actually publishing its results, run:{{{
56 domtool -tc $FILENAME}}}
57
58 Here, `-tc` stands for "type-check." The Domtool language is designed to capture all rules of which configuration is valid and which isn't in its parsing and typing rules, so using the `-tc` option ''should'' enable you to find any bugs in your configuration. We might have bugs in our implementations of the configuration directives from time to time, but `-tc` should be sufficient to help you find your own bugs.
59
60 Note that using your `~/.domtool` directory as a scratch space with lots of stray files is a bad idea, especially if you have multiple files representing different alternatives for configuring the same domain. Sometimes we make a change to Domtool that requires reprocessing all user configuration. In such cases, we run every file found in any user's `~/.domtool` directory. In that case, your `~/.domtool` files will be run in an arbitrary order, including any files that you have been thinking of as "test cases." It just might happen that the "test cases" end up overriding the "real" files. Also, if ''any'' file in your `~/.domtool` fails to type-check, we will unpublish ''all'' of your domains automatically. In summary, use another directory for storing tests, and run them by specifying explicit filename arguments to `domtool`, possibly with the `-tc` option.
61
62 = Permissions =
63
64 Now let's put on our Evil Hacker from the Seventh Circle of Hell hats. If you write this to a file `hcoop.net`:
65 {{{dom "hcoop.net" with
66 end;}}}
67 and run:{{{
68 domtool hcoop.net}}}
69 you should see an error message like:
70 {{{hcoop.net:0.0-1.14:error: Function argument has wrong type.
71 Expression: "hcoop.net"
72 Actual type: string
73 Needed type: your_domain}}}
74
75 What this is saying is that you are only allowed to use `dom` with domains that '''you''' are allowed to configure. You tried to configure `hcoop.net`, which is not one of those domains, and so is treated like an arbitrary string (sequence of characters). The type checker has saved the day, and the Evil Hacker is prevented from mucking with `hcoop.net` configuration.
76
77 How exactly does DomTool determine which domains you're allowed to configure? It uses a general permissions system based on access control lists. You can list all of your permissions by running:{{{
78 domtool-admin perms}}}
79 You should see output like this:
80 {{{Permissions for you:
81 domain: you.com you.net you.org
82 path: /afs/hcoop.net/user/y/yo/you
83 user: you}}}
84 where `you` stands for your username. The `domain` list gives the Internet domains to which you've been granted configuration rights. `user` lists the UNIX users as whom you may run programs, and `path` gives the filesystem paths that you're allowed to reference in your configurations. You have rights to all subdirectories of `path` entries, too.
85
86 You might like to perform some other queries on the permissions database, too. For instance, you might like to know which member owns `someone.com`. You could run:{{{
87 domtool-admin whohas domain someone.com}}}
88 and hopefully get back a reply like:{{{
89 whohas domain / someone.com: someone}}}
90
91 In general, `domtool-admin whohas $CLASS $VALUE` will list every user who has `$VALUE` in the `$CLASS` row of his permissions table.
92
93 = Nested configuration directives =
94
95 Let's look under the hood at what `dom` is doing by writing an equivalent configuration file that doesn't use it.
96 {{{domain "$DOMAIN" with
97 dns (dnsNS "ns1.hcoop.net");
98 dns (dnsNS "ns3.hcoop.net");
99
100 dns (dnsA "www" web_ip);
101
102 handleMail;
103 catchAllAlias "$USER";
104
105 vhost "www" with
106 end;
107 end;}}}
108
109 Now we see what that `with..end` syntax was about: it relates to '''nested configuration directives'''. Both `dom` and the more primitive `domain` directive take additional configuration specific to the named domain. Everything we include here inside `domain` could also have been included inside a `dom` use, though it would be redundant.
110
111 The contents of the `domain` block are a series of DomTool language expressions that evaluate to '''actions'''. Each action is given using consistent programming language syntax, rather than the ad-hoc configuration syntaxes used by daemons like Apache and Exim. This means that the directives are sometimes slightly more verbose, but they are much easier for humans and machines to parse, since no directive-specific ad-hoc syntax information is required.
112
113 Let's step through the nested directives one by one to explain their meanings.
114
115 The `dns` lines register DNS mappings to be included in `$DOMAIN`'s zone. `dnsNS` records list the authoritative nameservers in order. `dnsA` records provide mappings from hostnames to IP addresses. `web_ip` is a variable containing the IP address of our default web server for member use, defined in the standard library.
116
117 `handleMail` asks Exim to provide relaying for any e-mail message addressed to any address at `$DOMAIN`.
118
119 `catchAllAlias "$USER"` directs Exim to deposit any mail addressed to any user at `$DOMAIN` in `$USER`'s mailbox.
120
121 The `vhost` directive demonstrates several layers of nested configuration. It declares an Apache virtual host named `www.$DOMAIN`. We could have included further Apache-specific configuration inside the `vhost` directive.
122
123 = Configuration contexts =
124
125 Not all configuration directives make sense in all contexts. For instance, it doesn't make sense to specify a URL rewrite rule outside of a `vhost` directive. The DomTool language uses a concept of '''contexts''' or '''predicates''' to enforce correct usage of directives.
126
127 To illustrate, let's try breaking the rule we just gave in our example:
128 {{{dom "hcoop.net" with
129 alias "/doc" "/usr/local/doc"
130 end;}}}
131
132 We ask for the URI prefix `doc/` to be mapped to file path `/usr/local/doc`. The `alias` directive is only allowed inside `vhost`s, so we get an error like this:
133 {{{hcoop.net:0.0-3.4:error: Context incompatibility for nested action.
134 Have: Domain
135 Need: Vhost}}}
136
137 This one's simple enough. We're in a `Domain`, but we need to be in a `Vhost` to use that directive. In full generality, DomTool's context specification language is a small logic that can be used to express much more complicated conditions, while maintaining the ability for the interpreter to check proper usage automatically. See the DomTool/LanguageReference for a full specification.
138
139 = Environment variables =
140
141 DomTool has its own concept of typed '''environment variables''' that are used to tweak parameters of configuration directives. Here's an example to demonstrate how they're used and why they're useful.
142
143 Running this configuration:
144 {{{vhost "www" with
145 end;}}}
146 gives you an Apache virtual host that serves documents out of `~/public_html`. If you wanted to serve documents out of `$DIR` instead, you could run:
147 {{{vhost "www" where
148 DocumentRoot = "$DIR"
149 with
150 end;}}}
151 Maybe you want to use the same document root for two different virtual hosts. In that case, you could use:
152 {{{let
153 DocumentRoot = "$DIR"
154 in
155 vhost "www" with
156 end;
157
158 vhost "www2" with
159 end;
160 end;}}}
161 Both of these alternatives involve assigning a new value to the '''environment variable''' `DocumentRoot` of type `your_path`, the type of filesystem paths that you may reference in configuration. Both `where` and `let` only introduce ''local values'' for environment variables. That is, once the `let` or the expression with the `where` clause has finished, it undoes changes to the environment made in the `where` clause or the first part of the `let`. This helps you maintain neat code that doesn't rely too much on global state.
162
163 As this example hopefully shows, environment variables are useful because they make it more pleasant to use highly-customizable configuration directives. The less-commonly-configured aspects of a directive can be taken in as environment variables rather than normal arguments. That way, you don't need to write any code to deal with them when you are happy with their default values. When you ''do'' want to set a non-standard value, you can use a construct like `let` to apply it to multiple directives at once.
164
165 = Removing a domain =
166
167 When you no longer want to host a domain `$DOMAIN` with HCoop, do the following:
168
169 * Remove all mentions of `$DOMAIN` from the files in your `~/.domtool`.
170 * Run: {{{
171 domtool-admin rmdom $DOMAIN
172 }}}
173
174 The second step should fail if you haven't been granted permission to configure `$DOMAIN`. If you finish both steps successfully, then none of the shared HCoop daemons should serve anything related to `$DOMAIN` anymore.
175
176 = Further reading =
177
178 We're purposely cutting off this user guide at this shallow level of detail. The best thing to read next is the ["DomTool/Examples"], which should introduce by example all of the language features and configuration directives that you're likely to use. If you want to understand the type error messages that the interpreter generates as more than just "there is a problem somewhere," then you'll probably want to learn a bit more about the language.
179
180 For a more in-depth understanding of DomTool, including how to build and use your own directives, see the DomTool/LanguageReference. The [http://deleuze.hcoop.net/domtool/ standard library reference] presents all of the standard directives with full DomTool type information. We've glossed over details of the type system in this guide, but members comfortable with ML or Haskell programming will probably find this formal documentation the easiest to use, since types express very succinctly how directives may be used.
181
182 The main DomTool page links to all of these resources and several more.