svn:keywords
[bootmanager.git] / source / steps / InstallBootstrapFS.py
1 #!/usr/bin/python
2 #
3 # $Id$
4 # $URL$
5 #
6 # Copyright (c) 2003 Intel Corporation
7 # All rights reserved.
8 #
9 # Copyright (c) 2004-2007 The Trustees of Princeton University
10 # All rights reserved.
11 # expected /proc/partitions format
12
13 import os, sys, string
14 import popen2
15 import shutil
16 import traceback 
17
18 from Exceptions import *
19 import utils
20 import BootServerRequest
21 import BootAPI
22
23
24 def Run( vars, log ):
25     """
26     Download enough files to run rpm and yum from a chroot in
27     the system image directory
28     
29     Expect the following variables from the store:
30     SYSIMG_PATH          the path where the system image will be mounted
31     PARTITIONS           dictionary of generic part. types (root/swap)
32                          and their associated devices.
33     NODE_ID              the id of this machine
34     
35     Sets the following variables:
36     TEMP_BOOTCD_PATH     where the boot cd is remounted in the temp
37                          path
38     ROOT_MOUNTED         set to 1 when the the base logical volumes
39                          are mounted.
40     """
41
42     log.write( "\n\nStep: Install: bootstrapfs tarball.\n" )
43
44     # make sure we have the variables we need
45     try:
46         SYSIMG_PATH= vars["SYSIMG_PATH"]
47         if SYSIMG_PATH == "":
48             raise ValueError, "SYSIMG_PATH"
49
50         PARTITIONS= vars["PARTITIONS"]
51         if PARTITIONS == None:
52             raise ValueError, "PARTITIONS"
53
54         NODE_ID= vars["NODE_ID"]
55         if NODE_ID == "":
56             raise ValueError, "NODE_ID"
57
58     except KeyError, var:
59         raise BootManagerException, "Missing variable in vars: %s\n" % var
60     except ValueError, var:
61         raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
62
63
64     try:
65         # make sure the required partitions exist
66         val= PARTITIONS["root"]
67         val= PARTITIONS["swap"]
68         val= PARTITIONS["vservers"]
69     except KeyError, part:
70         log.write( "Missing partition in PARTITIONS: %s\n" % part )
71         return 0   
72
73     bs_request= BootServerRequest.BootServerRequest(vars)
74     
75     log.write( "turning on swap space\n" )
76     utils.sysexec( "swapon %s" % PARTITIONS["swap"], log )
77
78     # make sure the sysimg dir is present
79     utils.makedirs( SYSIMG_PATH )
80
81     log.write( "mounting root file system\n" )
82     utils.sysexec( "mount -t ext3 %s %s" % (PARTITIONS["root"],SYSIMG_PATH), log )
83
84     log.write( "mounting vserver partition in root file system\n" )
85     utils.makedirs( SYSIMG_PATH + "/vservers" )
86     utils.sysexec( "mount -t ext3 %s %s/vservers" % (PARTITIONS["vservers"],
87                                                      SYSIMG_PATH), log )
88
89     vars['ROOT_MOUNTED']= 1
90
91     # fetch deployment tag (like, 'alpha' or the like)
92     try:
93         deployment = BootAPI.call_api_function(vars, "GetNodeDeployment", (NODE_ID,) )
94     except:
95         log.write("WARNING : Failed to query tag 'deployment'\n")
96         deployment = ""
97
98     # which extensions are we part of ?
99     utils.breakpoint("Checking for the extension(s) tags")
100     extensions = []
101     try:
102         extension_tag = BootAPI.call_api_function(vars, "GetNodeExtensions", (NODE_ID,) )
103         if extension_tag:
104             extensions = extension_tag.split()
105
106     except:
107         log.write("WARNING : Failed to query tag 'extensions'\n")
108         log.write(traceback.format_exc())
109
110     if not extensions:
111         log.write("installing only core software\n")
112     
113     # check if the plain-bootstrapfs tag is set
114     download_suffix=".tar.bz2"
115     untar_option="-j"
116     try:
117         if BootAPI.call_api_function (vars, "GetNodePlainBootstrapfs", (NODE_ID,) ):
118             download_suffix=".tar"
119             untar_option=""
120     except:
121         log.write("WARNING : Failed to query tag 'plain-bootstrapfs'\n")
122         log.write(traceback.format_exc())
123
124     if not untar_option:
125         log.write("Using uncompressed bootstrapfs images\n")
126
127     # see also GetBootMedium in PLCAPI that does similar things
128     # figuring the default node family:
129     # (1) get node's tags 'arch' and 'pldistro'
130     # (2) if unsuccessful search /etc/planetlab/nodefamily on the bootcd
131     # (3) if that fails, set to planetlab-i386
132
133     try:
134         api_pldistro = BootAPI.call_api_function(vars, "GetNodePldistro", (NODE_ID,) )
135     except:
136         log.write("WARNING : Failed to query tag 'pldistro'\n")
137         api_pldistro = None
138     try:
139         api_arch = BootAPI.call_api_function(vars, "GetNodeArch", (NODE_ID,) )
140     except:
141         log.write("WARNING : Failed to query tag 'arch'\n")
142         api_arch = None
143     try:
144         (etc_pldistro,etc_arch) = file("/etc/planetlab/nodefamily").read().strip().split("-")
145     except:
146         log.write("WARNING : Failed to parse /etc/planetlab/nodefamily\n")
147         (etc_pldistro,etc_arch)=(None,None)
148     default_pldistro="planetlab"
149     default_arch="i386"
150
151     if api_pldistro:
152         pldistro = api_pldistro
153         log.write ("Using pldistro from pldistro API tag\n")
154     elif etc_pldistro:
155         pldistro = etc_pldistro
156         log.write ("Using pldistro from /etc/planetlab/nodefamily\n")
157     else:
158         pldistro = default_pldistro
159         log.write ("Using default pldistro\n")
160
161     if api_arch:
162         arch = api_arch
163         log.write ("Using arch from arch API tag\n")
164     elif etc_arch:
165         arch = etc_arch
166         log.write ("Using arch from /etc/planetlab/nodefamily\n")
167     else:
168         arch = default_arch
169         log.write ("Using default arch\n")
170
171     log.write ("Using nodefamily=%s-%s\n"%(pldistro,arch))
172
173     # deployment has no arch nor extensions, let operators put what they want in there
174     if deployment:
175         bootstrapfs_names = [ deployment ]
176     else:
177         bootstrapfs_names = [ "%s-%s"%(x,arch) for x in [ pldistro ] + extensions ]
178
179     # download and extract support tarball for this step, which has
180     # everything we need to successfully run
181
182     # installing extensions through yum has been dismantled
183     yum_extensions = []
184     # download and extract support tarball for this step, 
185     for name in bootstrapfs_names:
186         tarball = "bootstrapfs-%s%s"%(name,download_suffix)
187         source_file= "/boot/%s" % (tarball)
188         dest_file= "%s/%s" % (SYSIMG_PATH, tarball)
189
190         # 30 is the connect timeout, 14400 is the max transfer time in
191         # seconds (4 hours)
192         log.write( "downloading %s\n" % source_file )
193         result= bs_request.DownloadFile( source_file, None, None,
194                                          1, 1, dest_file,
195                                          30, 14400)
196         if result:
197             log.write( "extracting %s in %s\n" % (dest_file,SYSIMG_PATH) )
198             result= utils.sysexec( "tar -C %s -xpf %s %s" % (SYSIMG_PATH,dest_file,untar_option), log )
199             log.write( "Done\n")
200             utils.removefile( dest_file )
201         else:
202             # the main tarball is required
203             if name == "%s-%s"%(pldistro,arch):
204                 raise BootManagerException, "Unable to download main tarball %s from server." % \
205                     source_file
206             else:
207                 log.write("tarball for %s not found, scheduling a yum attempt\n"%(name))
208                 yum_extensions.append(name)
209
210     # copy resolv.conf from the base system into our temp dir
211     # so DNS lookups work correctly while we are chrooted
212     log.write( "Copying resolv.conf to temp dir\n" )
213     utils.sysexec( "cp /etc/resolv.conf %s/etc/" % SYSIMG_PATH, log )
214
215     # Copy the boot server certificate(s) and GPG public key to
216     # /usr/boot in the temp dir.
217     log.write( "Copying boot server certificates and public key\n" )
218
219     if os.path.exists("/usr/boot"):
220         utils.makedirs(SYSIMG_PATH + "/usr")
221         shutil.copytree("/usr/boot", SYSIMG_PATH + "/usr/boot")
222     elif os.path.exists("/usr/bootme"):
223         utils.makedirs(SYSIMG_PATH + "/usr/boot")
224         boot_server = file("/usr/bootme/BOOTSERVER").readline().strip()
225         shutil.copy("/usr/bootme/cacert/" + boot_server + "/cacert.pem",
226                     SYSIMG_PATH + "/usr/boot/cacert.pem")
227         file(SYSIMG_PATH + "/usr/boot/boot_server", "w").write(boot_server)
228         shutil.copy("/usr/bootme/pubring.gpg", SYSIMG_PATH + "/usr/boot/pubring.gpg")
229         
230     # For backward compatibility
231     if os.path.exists("/usr/bootme"):
232         utils.makedirs(SYSIMG_PATH + "/mnt/cdrom")
233         shutil.copytree("/usr/bootme", SYSIMG_PATH + "/mnt/cdrom/bootme")
234
235     # Import the GPG key into the RPM database so that RPMS can be verified
236     utils.makedirs(SYSIMG_PATH + "/etc/pki/rpm-gpg")
237     utils.sysexec("gpg --homedir=/root --export --armor" \
238                   " --no-default-keyring --keyring %s/usr/boot/pubring.gpg" \
239                   " >%s/etc/pki/rpm-gpg/RPM-GPG-KEY-planetlab" % (SYSIMG_PATH, SYSIMG_PATH))
240     utils.sysexec_chroot(SYSIMG_PATH, "rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-planetlab")
241
242     # the yum config has changed entirely; 
243     # in addition yum installs have more or less never worked - let's forget about this
244     # maybe NodeManager could profitably do the job instead
245     if yum_extensions:
246         log.write("WARNING : %r yum installs for node extensions are not supported anymore\n"%yum_extensions)
247
248     return 1