3 # Copyright (c) 2003 Intel Corporation
6 # Copyright (c) 2004-2007 The Trustees of Princeton University
8 # expected /proc/partitions format
16 from Exceptions import *
18 import BootServerRequest
24 Download core + extensions bootstrapfs tarballs and install on the hard drive
26 Expect the following variables from the store:
27 SYSIMG_PATH the path where the system image will be mounted
28 PARTITIONS dictionary of generic part. types (root/swap)
29 and their associated devices.
30 NODE_ID the id of this machine
32 Sets the following variables:
33 TEMP_BOOTCD_PATH where the boot cd is remounted in the temp
35 ROOT_MOUNTED set to 1 when the the base logical volumes
39 log.write("\n\nStep: Install: bootstrapfs tarball.\n")
41 # make sure we have the variables we need
43 SYSIMG_PATH = vars["SYSIMG_PATH"]
45 raise ValueError("SYSIMG_PATH")
47 PARTITIONS = vars["PARTITIONS"]
48 if PARTITIONS == None:
49 raise ValueError("PARTITIONS")
51 NODE_ID = vars["NODE_ID"]
53 raise ValueError("NODE_ID")
55 VERSION = vars['VERSION'] or 'unknown'
57 except KeyError as var:
58 raise BootManagerException("Missing variable in vars: {}\n".format(var))
59 except ValueError as var:
60 raise BootManagerException("Variable in vars, shouldn't be: {}\n".format(var))
64 # make sure the required partitions exist
65 val = PARTITIONS["root"]
66 val = PARTITIONS["swap"]
67 val = PARTITIONS["vservers"]
68 except KeyError, part:
69 log.write("Missing partition in PARTITIONS: {}\n".format(part))
72 bs_request = BootServerRequest.BootServerRequest(vars)
74 log.write("turning on swap space\n")
75 utils.sysexec("swapon {}".format(PARTITIONS["swap"]), log)
77 # make sure the sysimg dir is present
78 utils.makedirs(SYSIMG_PATH)
80 log.write("mounting root file system\n")
81 utils.sysexec("mount -t ext3 {} {}".format(PARTITIONS["root"], SYSIMG_PATH), log)
83 fstype = 'ext3' if vars['virt']=='vs' else 'btrfs'
85 one_partition = vars['ONE_PARTITION']=='1'
87 if (not one_partition):
88 log.write("mounting vserver partition in root file system (type {})\n".format(fstype))
89 utils.makedirs(SYSIMG_PATH + "/vservers")
90 utils.sysexec("mount -t {} {} {}/vservers"\
91 .format(fstype, PARTITIONS["vservers"], SYSIMG_PATH), log)
93 if vars['virt']=='lxc':
94 # NOTE: btrfs quota is supported from version: >= btrfs-progs-0.20 (f18+)
95 # older versions will not recongize the 'quota' command.
96 log.write("Enabling btrfs quota on {}/vservers\n".format(SYSIMG_PATH))
97 utils.sysexec_noerr("btrfs quota enable {}/vservers".format(SYSIMG_PATH))
99 vars['ROOT_MOUNTED'] = 1
101 # this is now retrieved in GetAndUpdateNodeDetails
102 nodefamily = vars['nodefamily']
103 extensions = vars['extensions']
104 # the 'plain' option is for tests mostly
105 plain = vars['plain']
107 download_suffix = ".tar"
108 uncompress_option = ""
109 log.write("Using plain bootstrapfs images\n")
111 download_suffix = ".tar.bz2"
112 uncompress_option = "-j"
113 log.write("Using compressed bootstrapfs images\n")
115 log.write ("Using nodefamily={}\n".format(nodefamily))
117 log.write("Installing only core software\n")
119 log.write("Requested extensions {}\n".format(extensions))
121 bootstrapfs_names = [ nodefamily ] + extensions
123 for name in bootstrapfs_names:
124 tarball = "bootstrapfs-{}{}".format(name, download_suffix)
125 source_file = "/boot/{}".format(tarball)
126 dest_file = "{}/{}".format(SYSIMG_PATH, tarball)
128 source_hash_file = "/boot/{}.sha1sum".format(tarball)
129 dest_hash_file = "{}/{}.sha1sum".format(SYSIMG_PATH, tarball)
131 time_beg = time.time()
132 log.write("downloading {}\n".format(source_file))
133 # 30 is the connect timeout, 14400 is the max transfer time in
135 result = bs_request.DownloadFile(source_file, None, None,
138 time_end = time.time()
139 duration = int(time_end - time_beg)
140 log.write("Done downloading ({} seconds)\n".format(duration))
142 # Download SHA1 checksum file
143 log.write("downloading sha1sum for {}\n".format(source_file))
144 result = bs_request.DownloadFile(source_hash_file, None, None,
145 1, 1, dest_hash_file,
148 log.write("verifying sha1sum for {}\n".format(source_file))
149 if not utils.check_file_hash(dest_file, dest_hash_file):
150 raise BootManagerException(
151 "FATAL: SHA1 checksum does not match between {} and {}"\
152 .format(source_file, source_hash_file))
155 time_beg = time.time()
156 log.write("extracting {} in {}\n".format(dest_file, SYSIMG_PATH))
157 result = utils.sysexec("tar -C {} -xpf {} {}".format(SYSIMG_PATH, dest_file, uncompress_option), log)
158 time_end = time.time()
159 duration = int(time_end - time_beg)
160 log.write("Done extracting ({} seconds)\n".format(duration))
161 utils.removefile(dest_file)
163 # the main tarball is required
164 if name == nodefamily:
165 raise BootManagerException(
166 "FATAL: Unable to download main tarball {} from server."\
167 .format(source_file))
168 # for extensions, just print a warning
170 log.write("WARNING: tarball for extension {} not found\n".format(name))
172 # copy resolv.conf from the base system into our temp dir
173 # so DNS lookups work correctly while we are chrooted
174 log.write("Copying resolv.conf to temp dir\n")
175 utils.sysexec("cp /etc/resolv.conf {}/etc/".format(SYSIMG_PATH), log)
177 # Copy the boot server certificate(s) and GPG public key to
178 # /usr/boot in the temp dir.
179 log.write("Copying boot server certificates and public key\n")
181 if os.path.exists("/usr/boot"):
182 utils.makedirs(SYSIMG_PATH + "/usr")
183 shutil.copytree("/usr/boot", SYSIMG_PATH + "/usr/boot")
184 elif os.path.exists("/usr/bootme"):
185 utils.makedirs(SYSIMG_PATH + "/usr/boot")
186 boot_server = file("/usr/bootme/BOOTSERVER").readline().strip()
187 shutil.copy("/usr/bootme/cacert/" + boot_server + "/cacert.pem",
188 SYSIMG_PATH + "/usr/boot/cacert.pem")
189 file(SYSIMG_PATH + "/usr/boot/boot_server", "w").write(boot_server)
190 shutil.copy("/usr/bootme/pubring.gpg", SYSIMG_PATH + "/usr/boot/pubring.gpg")
192 # For backward compatibility
193 if os.path.exists("/usr/bootme"):
194 utils.makedirs(SYSIMG_PATH + "/mnt/cdrom")
195 shutil.copytree("/usr/bootme", SYSIMG_PATH + "/mnt/cdrom/bootme")
197 # ONE_PARTITION => new distribution type
198 if (vars['ONE_PARTITION'] != '1'):
199 # Import the GPG key into the RPM database so that RPMS can be verified
200 utils.makedirs(SYSIMG_PATH + "/etc/pki/rpm-gpg")
201 utils.sysexec("gpg --homedir=/root --export --armor"
202 " --no-default-keyring --keyring {}/usr/boot/pubring.gpg"
203 " > {}/etc/pki/rpm-gpg/RPM-GPG-KEY-planetlab".format(SYSIMG_PATH, SYSIMG_PATH), log)
204 utils.sysexec_chroot(SYSIMG_PATH, "rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-planetlab", log)
206 # keep a log on the installed hdd
207 stamp = file(SYSIMG_PATH + "/bm-install.txt", 'a')
208 now = time.strftime("%Y-%b-%d @ %H:%M %Z", time.gmtime())
209 stamp.write("Hard drive installed by BootManager {}\n".format(VERSION))
210 stamp.write("Finished extraction of bootstrapfs on {}\n".format(now))
211 stamp.write("Using nodefamily {}\n".format(nodefamily))