check in all bootmanager sources
[bootmanager.git] / source / steps / InstallWriteConfig.py
1 # Copyright (c) 2003 Intel Corporation
2 # All rights reserved.
3
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met:
7
8 #     * Redistributions of source code must retain the above copyright
9 #       notice, this list of conditions and the following disclaimer.
10
11 #     * Redistributions in binary form must reproduce the above
12 #       copyright notice, this list of conditions and the following
13 #       disclaimer in the documentation and/or other materials provided
14 #       with the distribution.
15
16 #     * Neither the name of the Intel Corporation nor the names of its
17 #       contributors may be used to endorse or promote products derived
18 #       from this software without specific prior written permission.
19
20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
24 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32 # EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF
33 # YOUR JURISDICTION. It is licensee's responsibility to comply with any
34 # export regulations applicable in licensee's jurisdiction. Under
35 # CURRENT (May 2000) U.S. export regulations this software is eligible
36 # for export from the U.S. and can be downloaded by or otherwise
37 # exported or reexported worldwide EXCEPT to U.S. embargoed destinations
38 # which include Cuba, Iraq, Libya, North Korea, Iran, Syria, Sudan,
39 # Afghanistan and any other country to which the U.S. has embargoed
40 # goods and services.
41
42
43 import os, string
44
45 from Exceptions import *
46 import utils
47 from systeminfo import systeminfo
48 import BootAPI
49
50
51 def Run( vars, log ):
52
53     """
54     Writes out the following configuration files for the node:
55     /etc/fstab
56     /etc/hosts
57     /etc/sysconfig/network-scripts/ifcfg-eth0
58     /etc/resolv.conf (if applicable)
59     /etc/sysconfig/network
60     /etc/modprobe.conf
61     /etc/ssh/ssh_host_key
62     /etc/ssh/ssh_host_rsa_key
63     /etc/ssh/ssh_host_dsa_key
64     
65     Expect the following variables from the store:
66     VERSION                 the version of the install
67     SYSIMG_PATH             the path where the system image will be mounted
68                             (always starts with TEMP_PATH)
69     PARTITIONS              dictionary of generic part. types (root/swap)
70                             and their associated devices.
71     PLCONF_DIR              The directory to store the configuration file in
72     NETWORK_SETTINGS  A dictionary of the values from the network
73                                 configuration file
74     BOOT_CD_VERSION          A tuple of the current bootcd version
75     
76     Sets the following variables:
77     None
78     
79     """
80
81     log.write( "\n\nStep: Install: Writing configuration files.\n" )
82     
83     # make sure we have the variables we need
84     try:
85         VERSION= vars["VERSION"]
86         if VERSION == "":
87             raise ValueError, "VERSION"
88
89         SYSIMG_PATH= vars["SYSIMG_PATH"]
90         if SYSIMG_PATH == "":
91             raise ValueError, "SYSIMG_PATH"
92
93         PARTITIONS= vars["PARTITIONS"]
94         if PARTITIONS == None:
95             raise ValueError, "PARTITIONS"
96
97         PLCONF_DIR= vars["PLCONF_DIR"]
98         if PLCONF_DIR == "":
99             raise ValueError, "PLCONF_DIR"
100
101         NETWORK_SETTINGS= vars["NETWORK_SETTINGS"]
102         if NETWORK_SETTINGS == "":
103             raise ValueError, "NETWORK_SETTINGS"
104
105         BOOT_CD_VERSION= vars["BOOT_CD_VERSION"]
106         if BOOT_CD_VERSION == "":
107             raise ValueError, "BOOT_CD_VERSION"
108
109     except KeyError, var:
110         raise BootManagerException, "Missing variable in vars: %s\n" % var
111     except ValueError, var:
112         raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
113
114     try:
115         # we need to keys in PARTITIONS, root and swap, make sure
116         # they exist
117         val= PARTITIONS["root"]
118         val= PARTITIONS["swap"]
119         val= PARTITIONS["vservers"]
120         val= PARTITIONS["mapper-root"]
121         val= PARTITIONS["mapper-swap"]
122         val= PARTITIONS["mapper-vservers"]
123     except KeyError, part:
124         log.write( "Missing partition in PARTITIONS: %s\n" % part )
125         return 0
126     
127
128     log.write( "Setting local time to UTC\n" )
129     utils.sysexec( "chroot %s ln -sf /usr/share/zoneinfo/UTC /etc/localtime" % \
130                    SYSIMG_PATH, log )
131
132
133     log.write( "Enabling ntp at boot\n" )
134     utils.sysexec( "chroot %s chkconfig ntpd on" % SYSIMG_PATH, log )
135
136     log.write( "Creating system directory %s\n" % PLCONF_DIR )
137     if not utils.makedirs( "%s/%s" % (SYSIMG_PATH,PLCONF_DIR) ):
138         log.write( "Unable to create directory\n" )
139         return 0
140
141
142     log.write( "Writing network configuration\n" )
143     write_network_configuration( vars, log )
144
145     # write out the modprobe.conf file for the system. make sure
146     # the order of the ethernet devices are listed in the same order
147     # as the boot cd loaded the modules. this is found in /tmp/loadedmodules
148     # ultimately, the order will only match the boot cd order if
149     # the kernel modules have the same name - which should be true for the later
150     # version boot cds because they use the same kernel version.
151     # older boot cds use a 2.4.19 kernel, and its possible some of the network
152     # module names have changed, in which case the system might not boot
153     # if the network modules are activated in a different order that the
154     # boot cd.
155     log.write( "Writing /etc/modprobe.conf\n" )
156
157     sysinfo= systeminfo()
158     sysmods= sysinfo.get_system_modules(SYSIMG_PATH)
159     if sysmods is None:
160         raise BootManagerException, "Unable to get list of system modules."
161         
162     eth_count= 0
163     scsi_count= 0
164
165     modulesconf_file= file("%s/etc/modprobe.conf" % SYSIMG_PATH, "w" )
166
167     for type in sysmods:
168         if type == sysinfo.MODULE_CLASS_SCSI:
169             for a_mod in sysmods[type]:
170                 if scsi_count == 0:
171                     modulesconf_file.write( "alias scsi_hostadapter %s\n" %
172                                             a_mod )
173                 else:
174                     modulesconf_file.write( "alias scsi_hostadapter%d %s\n" %
175                                             (scsi_count,a_mod) )
176                 scsi_count= scsi_count + 1
177
178         elif type == sysinfo.MODULE_CLASS_NETWORK:
179             for a_mod in sysmods[type]:
180                 modulesconf_file.write( "alias eth%d %s\n" %
181                                         (eth_count,a_mod) )
182                 eth_count= eth_count + 1
183
184     modulesconf_file.close()
185     modulesconf_file= None
186
187
188     # dump the modprobe.conf file to the log (not to screen)
189     log.write( "Contents of new modprobe.conf file:\n" )
190     modulesconf_file= file("%s/etc/modprobe.conf" % SYSIMG_PATH, "r" )
191     contents= modulesconf_file.read()
192     log.write( contents + "\n" )
193     modulesconf_file.close()
194     modulesconf_file= None
195     log.write( "End contents of new modprobe.conf file.\n" )
196
197     log.write( "Writing system /etc/fstab\n" )
198     fstab= file( "%s/etc/fstab" % SYSIMG_PATH, "w" )
199     fstab.write( "%s           none        swap      sw        0 0\n" % \
200                  PARTITIONS["mapper-swap"] )
201     fstab.write( "%s           /           ext3      defaults  0 0\n" % \
202                  PARTITIONS["mapper-root"] )
203     fstab.write( "%s           /vservers   ext3      tagxid,defaults  0 0\n" % \
204                  PARTITIONS["mapper-vservers"] )
205     fstab.write( "none         /proc       proc      defaults  0 0\n" )
206     fstab.write( "none         /dev/shm    tmpfs     defaults  0 0\n" )
207     fstab.write( "none         /dev/pts    devpts    defaults  0 0\n" )
208     fstab.write( "none         /rcfs       rcfs      defaults  0 0\n" )
209     fstab.close()
210
211
212     log.write( "Writing system /etc/issue\n" )
213     issue= file( "%s/etc/issue" % SYSIMG_PATH, "w" )
214     issue.write( "PlanetLab Node: \\n\n" )
215     issue.write( "Kernel \\r on an \\m\n" )
216     issue.write( "http://www.planet-lab.org\n\n" )
217     issue.close()
218
219     log.write( "Setting up authentication (non-ssh)\n" )
220     utils.sysexec( "chroot %s authconfig --nostart --kickstart --enablemd5 " \
221                    "--enableshadow" % SYSIMG_PATH, log )
222     utils.sysexec( "sed -e 's/^root\:\:/root\:*\:/g' " \
223                    "%s/etc/shadow > %s/etc/shadow.new" % \
224                    (SYSIMG_PATH,SYSIMG_PATH), log )
225     utils.sysexec( "chroot %s mv " \
226                    "/etc/shadow.new /etc/shadow" % SYSIMG_PATH, log )
227     utils.sysexec( "chroot %s chmod 400 /etc/shadow" % SYSIMG_PATH, log )
228
229     # if we are setup with dhcp, copy the current /etc/resolv.conf into
230     # the system image so we can run programs inside that need network access
231     method= ""
232     try:
233         method= vars['NETWORK_SETTINGS']['method']
234     except:
235         pass
236     
237     if method == "dhcp":
238         utils.sysexec( "cp /etc/resolv.conf %s/etc/" % SYSIMG_PATH, log )
239
240     # the kernel rpm should have already done this, so don't fail the
241     # install if it fails
242     log.write( "Mounting /proc in system image\n" )
243     utils.sysexec_noerr( "mount -t proc proc %s/proc" % SYSIMG_PATH, log )
244
245     # mkinitrd references both /etc/modprobe.conf and /etc/fstab
246     # as well as /proc/lvm/global. The kernel RPM installation
247     # likely created an improper initrd since these files did not
248     # yet exist. Re-create the initrd here.
249     log.write( "Making initrd\n" )
250
251     # trick mkinitrd in case the current environment does not have device mapper
252     fake_root_lvm= 0
253     if not os.path.exists( "%s/%s" % (SYSIMG_PATH,PARTITIONS["mapper-root"]) ):
254         fake_root_lvm= 1
255         utils.makedirs( "%s/dev/mapper" % SYSIMG_PATH )
256         rootdev= file( "%s/%s" % (SYSIMG_PATH,PARTITIONS["mapper-root"]), "w" )
257         rootdev.close()
258
259     utils.sysexec( "chroot %s sh -c '" \
260                    "kernelversion=`ls /lib/modules | tail -1` && " \
261                    "rm -f /boot/initrd-$kernelversion.img && " \
262                    "mkinitrd /boot/initrd-$kernelversion.img $kernelversion'" % \
263                    SYSIMG_PATH, log )
264
265     if fake_root_lvm == 1:
266         utils.removefile( "%s/%s" % (SYSIMG_PATH,PARTITIONS["mapper-root"]) )
267
268     log.write( "Writing node install version\n" )
269     utils.makedirs( "%s/etc/planetlab" % SYSIMG_PATH )
270     ver= file( "%s/etc/planetlab/install_version" % SYSIMG_PATH, "w" )
271     ver.write( "%s\n" % VERSION )
272     ver.close()
273
274     log.write( "Creating ssh host keys\n" )
275     key_gen_prog= "/usr/bin/ssh-keygen"
276
277     log.write( "Generating SSH1 RSA host key:\n" )
278     key_file= "/etc/ssh/ssh_host_key"
279     utils.sysexec( "chroot %s %s -q -t rsa1 -f %s -C '' -N ''" %
280                    (SYSIMG_PATH,key_gen_prog,key_file), log )
281     utils.sysexec( "chmod 600 %s/%s" % (SYSIMG_PATH,key_file), log )
282     utils.sysexec( "chmod 644 %s/%s.pub" % (SYSIMG_PATH,key_file), log )
283     
284     log.write( "Generating SSH2 RSA host key:\n" )
285     key_file= "/etc/ssh/ssh_host_rsa_key"
286     utils.sysexec( "chroot %s %s -q -t rsa -f %s -C '' -N ''" %
287                    (SYSIMG_PATH,key_gen_prog,key_file), log )
288     utils.sysexec( "chmod 600 %s/%s" % (SYSIMG_PATH,key_file), log )
289     utils.sysexec( "chmod 644 %s/%s.pub" % (SYSIMG_PATH,key_file), log )
290     
291     log.write( "Generating SSH2 DSA host key:\n" )
292     key_file= "/etc/ssh/ssh_host_dsa_key"
293     utils.sysexec( "chroot %s %s -q -t dsa -f %s -C '' -N ''" %
294                    (SYSIMG_PATH,key_gen_prog,key_file), log )
295     utils.sysexec( "chmod 600 %s/%s" % (SYSIMG_PATH,key_file), log )
296     utils.sysexec( "chmod 644 %s/%s.pub" % (SYSIMG_PATH,key_file), log )
297
298     return 1
299
300
301
302 def write_network_configuration( vars, log ):
303     """
304     Write out the network configuration for this machine:
305     /etc/hosts
306     /etc/sysconfig/network-scripts/ifcfg-eth0
307     /etc/resolv.conf (if applicable)
308     /etc/sysconfig/network
309
310     It is assumed the caller mounted the root partition and the vserver partition
311     starting on SYSIMG_PATH - it is not checked here.
312
313     The values to be used for the network settings are to be set in vars
314     in the variable 'NETWORK_SETTINGS', which is a dictionary
315     with keys:
316
317      Key               Used by this function
318      -----------------------------------------------
319      node_id
320      node_key
321      method            x
322      ip                x
323      mac               x (optional)
324      gateway           x
325      network           x
326      broadcast         x
327      netmask           x
328      dns1              x
329      dns2              x (optional)
330      hostname          x
331      domainname        x
332     """
333
334     try:
335         SYSIMG_PATH= vars["SYSIMG_PATH"]
336         if SYSIMG_PATH == "":
337             raise ValueError, "SYSIMG_PATH"
338
339     except KeyError, var:
340         raise BootManagerException, "Missing variable in vars: %s\n" % var
341     except ValueError, var:
342         raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
343
344
345     try:
346         network_settings= vars['NETWORK_SETTINGS']
347     except KeyError, e:
348         raise BootManagerException, "No network settings found in vars."
349
350     try:
351         hostname= network_settings['hostname']
352         domainname= network_settings['domainname']
353         method= network_settings['method']
354         ip= network_settings['ip']
355         gateway= network_settings['gateway']
356         network= network_settings['network']
357         netmask= network_settings['netmask']
358         dns1= network_settings['dns1']
359     except KeyError, e:
360         raise BootManagerException, "Missing value %s in network settings." % str(e)
361
362     try:
363         dns2= ''
364         dns2= network_settings['dns2']
365     except KeyError, e:
366         pass
367
368         
369     log.write( "Writing /etc/hosts\n" )
370     hosts_file= file("%s/etc/hosts" % SYSIMG_PATH, "w" )    
371     hosts_file.write( "127.0.0.1       localhost\n" )
372     if method == "static":
373         hosts_file.write( "%s %s.%s\n" % (ip, hostname, domainname) )
374     hosts_file.close()
375     hosts_file= None
376     
377
378     log.write( "Writing /etc/sysconfig/network-scripts/ifcfg-eth0\n" )
379     eth0_file= file("%s/etc/sysconfig/network-scripts/ifcfg-eth0" %
380                     SYSIMG_PATH, "w" )
381     eth0_file.write( "DEVICE=eth0\n" )
382     if method == "static":
383         eth0_file.write( "BOOTPROTO=static\n" )
384         eth0_file.write( "IPADDR=%s\n" % ip )
385         eth0_file.write( "NETMASK=%s\n" % netmask )
386         eth0_file.write( "GATEWAY=%s\n" % gateway )
387     else:
388         eth0_file.write( "BOOTPROTO=dhcp\n" )
389         eth0_file.write( "DHCP_HOSTNAME=%s\n" % hostname )
390     eth0_file.write( "ONBOOT=yes\n" )
391     eth0_file.write( "USERCTL=no\n" )
392     eth0_file.close()
393     eth0_file= None
394
395     if method == "static":
396         log.write( "Writing /etc/resolv.conf\n" )
397         resolv_file= file("%s/etc/resolv.conf" % SYSIMG_PATH, "w" )
398         if dns1 != "":
399             resolv_file.write( "nameserver %s\n" % dns1 )
400         if dns2 != "":
401             resolv_file.write( "nameserver %s\n" % dns2 )
402         resolv_file.write( "search %s\n" % domainname )
403         resolv_file.close()
404         resolv_file= None
405
406     log.write( "Writing /etc/sysconfig/network\n" )
407     network_file= file("%s/etc/sysconfig/network" % SYSIMG_PATH, "w" )
408     network_file.write( "NETWORKING=yes\n" )
409     network_file.write( "HOSTNAME=%s.%s\n" % (hostname, domainname) )
410     if method == "static":
411         network_file.write( "GATEWAY=%s\n" % gateway )
412     network_file.close()
413     network_file= None
414