Commit | Line | Data |
---|---|---|
b7cfede0 BK |
1 | #!/usr/bin/perl -w |
2 | # Copyright (C) 2000 by Sam Hartman | |
3 | # This file may be copied either under the terms of the GNU GPL or the IBM | |
4 | # Public License either version 2 or later of the GPL or version 1.0 or later | |
5 | # of the IPL. | |
6 | ||
7 | use Term::ReadLine; | |
8 | use strict; | |
9 | use Debian::OpenAFS::ConfigUtils; | |
10 | use Getopt::Long; | |
11 | use Socket qw(inet_ntoa); | |
12 | use vars qw($admin $server $requirements_met $shutdown_needed); | |
13 | my $rl = new Term::ReadLine('afs-newcell'); | |
14 | ||
15 | # The default file server options are poor. Until they've been updated, use | |
16 | # the following from Harald Barth; it should be an improvement for most | |
17 | # people. | |
18 | my $fs_options = '-p 23 -busyat 600 -rxpck 400 -s 1200 -l 1200 -cb 65535' | |
19 | . ' -b 240 -vc 1200'; | |
20 | ||
21 | =head1 NAME | |
22 | ||
23 | afs-newcell - Set up initial database server for AFS cell | |
24 | ||
25 | =head1 SYNOPSIS | |
26 | ||
27 | B<afs-newcell> [B<--requirements-met>] [B<--admin> admin_user] | |
28 | ||
29 | =head1 DESCRIPTION | |
30 | ||
31 | This script sets up the initial AFS database and configures the first | |
32 | database/file server. | |
33 | ||
34 | The B<--requirements-met> option specifies that the initial requirements have | |
35 | been met and that the script can proceed without displaying the initial | |
36 | banner or asking for confirmation. | |
37 | ||
38 | The B<--admin> option specifies the name of the administrative user. This | |
39 | user will be given system:administrators and susers permission in the cell. | |
40 | ||
41 | =head1 AUTHOR | |
42 | ||
43 | Sam Hartman <hartmans@debian.org> | |
44 | ||
45 | =cut | |
46 | ||
47 | # Flush all output immediately. | |
48 | $| = 1; | |
49 | ||
50 | GetOptions ("requirements-met" => \$requirements_met, "admin=s" => \$admin); | |
51 | ||
52 | unless ($requirements_met) { | |
53 | print <<eoreqs; | |
54 | Prerequisites | |
55 | ||
56 | In order to set up a new AFS cell, you must meet the following: | |
57 | ||
58 | 1) You need a working Kerberos realm with Kerberos4 support. You | |
59 | should install Heimdal with KTH Kerberos compatibility or MIT | |
60 | Kerberos 5. | |
61 | ||
62 | 2) You need to create the single-DES AFS key and load it into | |
63 | /etc/openafs/server/KeyFile. If your cell's name is the same as | |
64 | your Kerberos realm then create a principal called afs. Otherwise, | |
65 | create a principal called afs/cellname in your realm. The cell | |
66 | name should be all lower case, unlike Kerberos realms which are all | |
67 | upper case. You can use asetkey from the openafs-krb5 package, or | |
68 | if you used AFS3 salt to create the key, the bos addkey command. | |
69 | ||
70 | 3) This machine should have a filesystem mounted on /vicepa. If you | |
71 | do not have a free partition, then create a large file by using dd | |
72 | to extract bytes from /dev/zero. Create a filesystem on this file | |
73 | and mount it using -oloop. | |
74 | ||
75 | 4) You will need an administrative principal created in a Kerberos | |
76 | realm. This principal will be added to susers and | |
77 | system:administrators and thus will be able to run administrative | |
78 | commands. Generally the user is a root or admin instance of some | |
79 | administrative user. For example if jruser is an administrator then | |
80 | it would be reasonable to create jruser/admin (or jruser/root) and | |
81 | specify that as the user to be added in this script. | |
82 | ||
83 | 5) The AFS client must not be running on this workstation. It will be | |
84 | at the end of this script. | |
85 | ||
86 | eoreqs | |
87 | #'# cperl-mode | |
88 | ||
89 | $_ = $rl->readline("Do you meet these requirements? [y/n] "); | |
90 | unless (/^y/i ) { | |
91 | print "Run this script again when you meet the requirements\n"; | |
92 | exit(1); | |
93 | } | |
94 | ||
95 | if ($> != 0) { | |
96 | die "This script should almost always be run as root. Use the\n" | |
97 | . "--requirements-met option to run as non-root.\n"; | |
98 | } | |
99 | } | |
100 | ||
101 | # Make sure the AFS client is not already running. | |
102 | open(MOUNT, "mount |") or die "Failed to run mount: $!\n"; | |
103 | while(<MOUNT>) { | |
104 | if (m:^AFS:) { | |
105 | print "The AFS client is currently running on this workstation.\n"; | |
106 | print "Please restart this script after running" | |
107 | . " service openafs-client stop\n"; | |
108 | exit(1); | |
109 | } | |
110 | } | |
111 | close MOUNT; | |
112 | ||
113 | # Make sure there is a keyfile. | |
114 | unless ( -f "/etc/openafs/server/KeyFile") { | |
115 | print "You do not have an AFS keyfile. Please create this using\n"; | |
116 | print "asetkey from openafs-krb5 or the bos addkey command\n"; | |
117 | exit(1); | |
118 | } | |
119 | ||
120 | # Stop the file server. | |
121 | print "If the fileserver is not running, this may hang for 30 seconds.\n"; | |
122 | run("service openafs-fileserver stop"); | |
123 | ||
124 | # Get the local hostname. Use the fully-qualified hostname to be safer. | |
125 | $server = `hostname -f`; | |
126 | chomp $server; | |
127 | my $ip = gethostbyname $server; | |
128 | if (inet_ntoa($ip) eq '127.0.0.1') { | |
129 | print "\n"; | |
130 | print "Your hostname $server resolves to 127.0.0.1, which AFS cannot\n"; | |
131 | print "cope with. Make sure your hostname resolves to a non-loopback\n"; | |
132 | print "IP address. (Check /etc/hosts and make sure that your hostname\n"; | |
133 | print "isn't listed on the 127.0.0.1 line. If it is, removing it from\n"; | |
134 | print "that line will probably solve this problem.)\n"; | |
135 | exit(1); | |
136 | } | |
137 | ||
138 | # Determine the admin principal. | |
139 | $admin = $rl->readline("What administrative principal should be used? ") | |
140 | unless $admin; | |
141 | print "\n"; | |
142 | die "Please specify an administrative user\n" unless $admin; | |
143 | my $afs_admin = $admin; | |
144 | $afs_admin =~ s:/:.:g; | |
145 | if ($afs_admin =~ /@/) { | |
146 | die "The administrative user must be in the same realm as the cell and\n" | |
147 | . "no realm may be specified.\n"; | |
148 | } | |
149 | ||
150 | # Determine the local cell. This should be configured via debconf, from the | |
151 | # openafs-client configuration, when openafs-fileserver is installed. | |
152 | open(CELL, "/etc/openafs/server/ThisCell") | |
153 | or die "Cannot open /etc/openafs/server/ThisCell: $!\n"; | |
154 | my $cell = <CELL>; | |
155 | chomp $cell; | |
156 | ||
157 | # Make sure the new cell is configured in the client CellServDB. | |
158 | open(CELLSERVDB, "/etc/openafs/CellServDB") | |
159 | or die "Cannot open /etc/openafs/CellServDB: $!\n"; | |
160 | my $found = 0; | |
161 | while (<CELLSERVDB>) { | |
162 | next unless /^>\Q$cell\E\s/; | |
163 | while (<CELLSERVDB>) { | |
164 | last if /^>/; | |
165 | my ($dbserver) = split ' '; | |
166 | if ($dbserver eq inet_ntoa($ip)) { | |
167 | $found = 1; | |
168 | last; | |
169 | } | |
170 | } | |
171 | last; | |
172 | } | |
173 | unless ($found) { | |
174 | print "\n"; | |
175 | print "The new cell $cell is not configured in /etc/openafs/CellServDB\n"; | |
176 | print "Add configuration like:\n\n"; | |
177 | print ">$cell\n"; | |
178 | print inet_ntoa($ip), "\t\t\t#$server\n\n"; | |
179 | print "to that file before continuing.\n"; | |
180 | exit(1); | |
181 | } | |
182 | ||
183 | # Write out a new CellServDB for the local cell containing only this server. | |
184 | if (-f "/etc/openafs/server/CellServDB") { | |
185 | print "/etc/openafs/server/CellServDB already exists, renaming to .old\n"; | |
186 | rename("/etc/openafs/server/CellServDB", | |
187 | "/etc/openafs/server/CellServDB.old") | |
188 | or die "Cannot rename /etc/openafs/server/CellServDB: $!\n"; | |
189 | } | |
190 | open(CELLSERVDB, "> /etc/openafs/server/CellServDB") | |
191 | or die "Cannot create /etc/openafs/server/CellServDB: $!\n"; | |
192 | print CELLSERVDB ">$cell\n"; | |
193 | print CELLSERVDB inet_ntoa($ip), "\t\t\t#$server\n"; | |
194 | close CELLSERVDB or die "Cannot write to /etc/openafs/server/CellServDB: $!\n"; | |
195 | ||
196 | # Now, we should be able to start bos and add the admin user. | |
197 | run("service openafs-fileserver start"); | |
198 | $shutdown_needed = 1; | |
199 | run("bos adduser $server $afs_admin -localauth"); | |
200 | unwind("bos removeuser $server $afs_admin -localauth"); | |
201 | ||
202 | # Create the initial protection database using pt_util. This is safer than | |
203 | # the standard mechanism of starting the cell in noauth mode until the first | |
204 | # user has been created. | |
205 | if (-f "/var/lib/openafs/db/prdb.DB0") { | |
206 | warn "ERROR: Protection database already exists; cell already partially\n"; | |
207 | warn "ERROR: created. If you do not want the current database, remove\n"; | |
208 | warn "ERROR: all files in /var/lib/openafs/db and then run this program\n"; | |
209 | warn "ERROR: again.\n"; | |
210 | exit(1); | |
211 | } | |
212 | print "\nCreating initial protection database. This will print some errors\n"; | |
213 | print "about an id already existing and a bad ubik magic. These errors can\n"; | |
214 | print "be safely ignored.\n\n"; | |
215 | open(PRDB, "| pt_util -p /var/lib/openafs/db/prdb.DB0 -w") | |
216 | or die "Unable to start pt_util: $!\n"; | |
217 | print PRDB "$afs_admin 128/20 1 -204 -204\n"; | |
218 | print PRDB "system:administrators 130/20 -204 -204 -204\n"; | |
219 | print PRDB " $afs_admin 1\n"; | |
220 | close PRDB; | |
221 | unwind("rm /var/lib/openafs/db/prdb*"); | |
222 | print "\n"; | |
223 | ||
224 | # We should now be able to start ptserver and vlserver. | |
225 | run("bos create $server ptserver simple /usr/lib/openafs/ptserver -localauth"); | |
226 | unwind("bos delete $server ptserver -localauth"); | |
227 | run("bos create $server vlserver simple /usr/lib/openafs/vlserver -localauth"); | |
228 | unwind("bos delete $server vlserver -localauth"); | |
229 | ||
230 | # Create a file server as well. | |
231 | run("bos create $server dafs dafs" | |
232 | . " -cmd '/usr/lib/openafs/dafileserver $fs_options'" | |
233 | . " -cmd /usr/lib/openafs/davolserver" | |
234 | . " -cmd /usr/lib/openafs/salvageserver" | |
235 | . " -cmd /usr/lib/openafs/dasalvager -localauth"); | |
236 | unwind("bos delete $server dafs -localauth"); | |
237 | ||
238 | # Make sure that there is no scheduled general restart time; it's not needed. | |
239 | run("bos setrestart $server -time never -general -localauth"); | |
240 | ||
241 | # Pause for a while for ubik to catch up. | |
242 | print "Waiting for database elections: "; | |
243 | sleep(30); | |
244 | print "done.\n"; | |
245 | ||
246 | # Past this point we want to control when bos shutdown happens. | |
247 | $shutdown_needed = 0; | |
248 | unwind("bos shutdown $server -localauth -wait"); | |
249 | run("vos create $server a root.afs -localauth"); | |
250 | unwind("vos remove $server a root.afs -localauth"); | |
251 | ||
252 | # We should now be able to bring up the client (it may need root.afs to exist | |
253 | # if not using dynroot). We override whatever default cell was configured for | |
254 | # the client, just in case it was pointing to some other cell. | |
255 | open(THIS, "> /etc/openafs/ThisCell") | |
256 | or die "ERROR: Cannot create /etc/openafs/ThisCell: $!\n"; | |
257 | print THIS "$cell\n"; | |
258 | close THIS or die "ERROR: Cannot write to /etc/openafs/ThisCell: $!\n"; | |
259 | run("service openafs-client force-start"); | |
260 | ||
261 | # Verify that AFS has managed to start. | |
262 | my $afs_running = 0; | |
263 | open(MOUNT, "mount |") or die "ERROR: Failed to run mount: $!\n"; | |
264 | while(<MOUNT>) { | |
265 | if (m:^AFS:) { | |
266 | $afs_running = 1; | |
267 | } | |
268 | } | |
269 | unless ($afs_running) { | |
270 | print "ERROR: The AFS client failed to start.\n"; | |
271 | print "ERROR: Please fix whatever problem kept it from running.\n"; | |
272 | exit(1); | |
273 | } | |
274 | print "\n"; | |
275 | print "Now, get tokens as $admin in the $cell cell.\n"; | |
276 | print "Then, run afs-rootvol.\n"; | |
277 | ||
278 | # Success, so clear the unwind commands. | |
279 | @unwinds = (); | |
280 | ||
281 | # If we fail before all the instances are created, we need to back out of | |
282 | # everything we did as much as possible. | |
283 | END { | |
284 | if ($shutdown_needed || @unwinds) { | |
285 | print "\nCell setup failed, ABORTING\n"; | |
286 | } | |
287 | system("bos shutdown $server -localauth -wait") if $shutdown_needed; | |
288 | run(pop @unwinds) while @unwinds; | |
289 | } |