|
| 1 | +From 2c0c50e89d4f172bb2abf723aef8474204c83afc Mon Sep 17 00:00:00 2001 |
| 2 | +From: Shreenidhi Shedi < [email protected]> |
| 3 | +Date: Tue, 21 Dec 2021 18:53:18 +0530 |
| 4 | +Subject: [PATCH] installer.py: fix installroot commands |
| 5 | + |
| 6 | +After this fix in tdnf: |
| 7 | +https://github.com/vmware/tdnf/commit/9d2ab6090c1b0dcba4f28763b042b2fd8da3c551 |
| 8 | + |
| 9 | +installroot option creates repodir if it doesn't exist inside given root |
| 10 | +path. |
| 11 | + |
| 12 | +This patch fixes it by providing repodir path using |
| 13 | +``` |
| 14 | +--setopt=reposdir=... option |
| 15 | +``` |
| 16 | + |
| 17 | +Other changes: |
| 18 | +Fixed a bunch of flake8 warnings in installer.py |
| 19 | +Change cachedir path to `.../var/cache/tdnf` |
| 20 | + |
| 21 | +Change-Id: Ibea9fdd555a03c366456c7efffa449defc1b5da7 |
| 22 | +Signed-off-by: Shreenidhi Shedi < [email protected]> |
| 23 | +--- |
| 24 | + photon_installer/installer.py | 107 +++++++++++++++++----------------- |
| 25 | + 1 file changed, 55 insertions(+), 52 deletions(-) |
| 26 | + |
| 27 | +diff --git a/photon_installer/installer.py b/photon_installer/installer.py |
| 28 | +index e09941f..5d019e7 100755 |
| 29 | +--- a/photon_installer/installer.py |
| 30 | ++++ b/photon_installer/installer.py |
| 31 | +@@ -1,12 +1,11 @@ |
| 32 | + """ |
| 33 | + Photon installer |
| 34 | + """ |
| 35 | +-#/* |
| 36 | +-# * Copyright © 2020 VMware, Inc. |
| 37 | +-# * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-only |
| 38 | +-# */ |
| 39 | ++# /* |
| 40 | ++# * Copyright © 2020 VMware, Inc. |
| 41 | ++# * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-only |
| 42 | ++# */ |
| 43 | + # |
| 44 | +-# Author: Mahmoud Bassiouny <[email protected]> |
| 45 | + |
| 46 | + import subprocess |
| 47 | + import os |
| 48 | +@@ -25,13 +24,13 @@ |
| 49 | + from jsonwrapper import JsonWrapper |
| 50 | + from progressbar import ProgressBar |
| 51 | + from window import Window |
| 52 | +-from actionresult import ActionResult |
| 53 | + from networkmanager import NetworkManager |
| 54 | + from enum import Enum |
| 55 | + |
| 56 | + BIOSSIZE = 4 |
| 57 | + ESPSIZE = 10 |
| 58 | + |
| 59 | ++ |
| 60 | + class PartitionType(Enum): |
| 61 | + SWAP = 1 |
| 62 | + LINUX = 2 |
| 63 | +@@ -39,6 +38,7 @@ class PartitionType(Enum): |
| 64 | + ESP = 4 |
| 65 | + BIOS = 5 |
| 66 | + |
| 67 | ++ |
| 68 | + class Installer(object): |
| 69 | + """ |
| 70 | + Photon installer |
| 71 | +@@ -104,9 +104,9 @@ def __init__(self, working_directory="/mnt/photon-root", |
| 72 | + self.installer_path = os.path.dirname(os.path.abspath(__file__)) |
| 73 | + self.tdnf_conf_path = self.working_directory + "/tdnf.conf" |
| 74 | + self.tdnf_repo_path = self.working_directory + "/photon-local.repo" |
| 75 | +- self.rpm_cache_dir = self.photon_root + '/cache/tdnf/photon-local/rpms' |
| 76 | ++ self.rpm_cache_dir = self.photon_root + '/var/cache/tdnf/photon-local/rpms' |
| 77 | + # used by tdnf.conf as cachedir=, tdnf will append the rest |
| 78 | +- self.rpm_cache_dir_short = self.photon_root + '/cache/tdnf' |
| 79 | ++ self.rpm_cache_dir_short = self.photon_root + '/var/cache/tdnf' |
| 80 | + |
| 81 | + self.setup_grub_command = os.path.dirname(__file__)+"/mk-setup-grub.sh" |
| 82 | + |
| 83 | +@@ -116,7 +116,7 @@ def __init__(self, working_directory="/mnt/photon-root", |
| 84 | + """ |
| 85 | + create, append and validate configuration date - install_config |
| 86 | + """ |
| 87 | +- def configure(self, install_config, ui_config = None): |
| 88 | ++ def configure(self, install_config, ui_config=None): |
| 89 | + if install_config and 'insecure_installation' in install_config: |
| 90 | + insecure_installation = install_config.pop('insecure_installation') |
| 91 | + |
| 92 | +@@ -155,7 +155,6 @@ def configure(self, install_config, ui_config = None): |
| 93 | + |
| 94 | + self.install_config = install_config |
| 95 | + |
| 96 | +- |
| 97 | + def execute(self): |
| 98 | + if 'setup_grub_script' in self.install_config: |
| 99 | + self.setup_grub_command = self.install_config['setup_grub_script'] |
| 100 | +@@ -247,17 +246,16 @@ def _add_defaults(self, install_config): |
| 101 | + install_config['search_path'].append(dirname) |
| 102 | + |
| 103 | + if 'linux_flavor' not in install_config: |
| 104 | +- if install_config.get('install_linux_esx', False) == True: |
| 105 | ++ if install_config.get('install_linux_esx', False): |
| 106 | + install_config['linux_flavor'] = "linux-esx" |
| 107 | + else: |
| 108 | +- available_flavors=[] |
| 109 | ++ available_flavors = [] |
| 110 | + for flavor in self.all_linux_flavors: |
| 111 | + if flavor in install_config['packages']: |
| 112 | + available_flavors.append(flavor) |
| 113 | + if len(available_flavors) == 1: |
| 114 | + install_config['linux_flavor'] = available_flavors[0] |
| 115 | + |
| 116 | +- |
| 117 | + install_config['install_linux_esx'] = False |
| 118 | + |
| 119 | + # Default Photon docker image |
| 120 | +@@ -277,7 +275,7 @@ def _check_install_config(self, install_config): |
| 121 | + if len(unknown_keys) > 0: |
| 122 | + return "Unknown install_config keys: " + ", ".join(unknown_keys) |
| 123 | + |
| 124 | +- if not 'disk' in install_config: |
| 125 | ++ if 'disk' not in install_config: |
| 126 | + return "No disk configured" |
| 127 | + |
| 128 | + # For Ostree install_config['packages'] will be empty list, because ostree |
| 129 | +@@ -507,9 +505,9 @@ def _bind_installer(self): |
| 130 | + """ |
| 131 | + # Make the photon_root/installer directory if not exits |
| 132 | + if(self.cmd.run(['mkdir', '-p', |
| 133 | +- os.path.join(self.photon_root, "installer")]) != 0 or |
| 134 | ++ os.path.join(self.photon_root, "installer")]) != 0 or |
| 135 | + self.cmd.run(['mount', '--bind', self.installer_path, |
| 136 | +- os.path.join(self.photon_root, "installer")]) != 0): |
| 137 | ++ os.path.join(self.photon_root, "installer")]) != 0): |
| 138 | + self.logger.error("Fail to bind installer") |
| 139 | + self.exit_gracefully() |
| 140 | + |
| 141 | +@@ -548,9 +546,9 @@ def _unbind_repo_dir(self): |
| 142 | + |
| 143 | + def _get_partuuid(self, path): |
| 144 | + partuuid = subprocess.check_output(['blkid', '-s', 'PARTUUID', '-o', 'value', path], |
| 145 | +- universal_newlines=True).rstrip('\n') |
| 146 | ++ universal_newlines=True).rstrip('\n') |
| 147 | + # Backup way to get uuid/partuuid. Leave it here for later use. |
| 148 | +- #if partuuidval == '': |
| 149 | ++ # if partuuidval == '': |
| 150 | + # sgdiskout = Utils.runshellcommand( |
| 151 | + # "sgdisk -i 2 {} ".format(disk_device)) |
| 152 | + # partuuidval = (re.findall(r'Partition unique GUID.*', |
| 153 | +@@ -561,7 +559,7 @@ def _get_uuid(self, path): |
| 154 | + return subprocess.check_output(['blkid', '-s', 'UUID', '-o', 'value', path], |
| 155 | + universal_newlines=True).rstrip('\n') |
| 156 | + |
| 157 | +- def _create_fstab(self, fstab_path = None): |
| 158 | ++ def _create_fstab(self, fstab_path=None): |
| 159 | + """ |
| 160 | + update fstab |
| 161 | + """ |
| 162 | +@@ -661,9 +659,12 @@ def _initialize_system(self): |
| 163 | + self.exit_gracefully() |
| 164 | + |
| 165 | + # Install filesystem rpm |
| 166 | +- tdnf_cmd = "tdnf install filesystem --releasever {0} --installroot {1} --assumeyes -c {2}".format( |
| 167 | +- self.install_config['photon_release_version'], self.photon_root, |
| 168 | +- self.tdnf_conf_path) |
| 169 | ++ tdnf_cmd = ("tdnf install -y filesystem --releasever {0} " |
| 170 | ++ "--installroot {1} -c {2} " |
| 171 | ++ "--setopt=reposdir={3}").format(self.install_config['photon_release_version'], |
| 172 | ++ self.photon_root, |
| 173 | ++ self.tdnf_conf_path, |
| 174 | ++ self.working_directory) |
| 175 | + retval = self.cmd.run(tdnf_cmd) |
| 176 | + if retval != 0: |
| 177 | + retval = self.cmd.run(['docker', 'run', |
| 178 | +@@ -683,8 +684,7 @@ def _initialize_system(self): |
| 179 | + } |
| 180 | + for device, (mode, dev_type, major, minor) in devices.items(): |
| 181 | + os.mknod(os.path.join(self.photon_root, "dev", device), |
| 182 | +- mode | dev_type, os.makedev(major, minor)) |
| 183 | +- |
| 184 | ++ mode | dev_type, os.makedev(major, minor)) |
| 185 | + |
| 186 | + def _mount_special_folders(self): |
| 187 | + for d in ["/proc", "/dev", "/dev/pts", "/sys"]: |
| 188 | +@@ -751,8 +751,8 @@ def _setup_grub(self): |
| 189 | + retval = self.cmd.run('grub2-install --target=i386-pc --force --boot-directory={} {}'.format(self.photon_root + "/boot", self.install_config['disk'])) |
| 190 | + if retval != 0: |
| 191 | + retval = self.cmd.run(['grub-install', '--target=i386-pc', '--force', |
| 192 | +- '--boot-directory={}'.format(self.photon_root + "/boot"), |
| 193 | +- self.install_config['disk']]) |
| 194 | ++ '--boot-directory={}'.format(self.photon_root + "/boot"), |
| 195 | ++ self.install_config['disk']]) |
| 196 | + if retval != 0: |
| 197 | + raise Exception("Unable to setup grub") |
| 198 | + |
| 199 | +@@ -823,6 +823,7 @@ def _adjust_packages_based_on_selected_flavor(self): |
| 200 | + Install slected linux flavor only |
| 201 | + """ |
| 202 | + redundant_linux_flavors = [] |
| 203 | ++ |
| 204 | + def filter_packages(package): |
| 205 | + package = package.split('-') |
| 206 | + if len(package) > 1: |
| 207 | +@@ -846,7 +847,7 @@ def filter_packages(package): |
| 208 | + else: |
| 209 | + flavor = "" |
| 210 | + redundant_linux_flavors.append(flavor) |
| 211 | +- self.install_config['packages'] = list(filter(filter_packages,self.install_config['packages'])) |
| 212 | ++ self.install_config['packages'] = list(filter(filter_packages, self.install_config['packages'])) |
| 213 | + |
| 214 | + def _add_packages_to_install(self, package): |
| 215 | + """ |
| 216 | +@@ -880,8 +881,6 @@ def _setup_install_repo(self): |
| 217 | + # want input RPMS to be removed after installation. |
| 218 | + if keepcache: |
| 219 | + conf_file.write("keepcache=1\n") |
| 220 | +- conf_file.write("repodir={}\n".format(self.working_directory)) |
| 221 | +- conf_file.write("cachedir={}\n".format(self.rpm_cache_dir_short)) |
| 222 | + |
| 223 | + def _install_additional_rpms(self): |
| 224 | + rpms_path = self.install_config.get('additional_rpms_path', None) |
| 225 | +@@ -889,7 +888,7 @@ def _install_additional_rpms(self): |
| 226 | + if not rpms_path or not os.path.exists(rpms_path): |
| 227 | + return |
| 228 | + |
| 229 | +- if self.cmd.run([ 'rpm', '--root', self.photon_root, '-U', rpms_path + '/*.rpm' ]) != 0: |
| 230 | ++ if self.cmd.run(['rpm', '--root', self.photon_root, '-U', rpms_path + '/*.rpm']) != 0: |
| 231 | + self.logger.info('Failed to install additional_rpms from ' + rpms_path) |
| 232 | + self.exit_gracefully() |
| 233 | + |
| 234 | +@@ -903,9 +902,13 @@ def _install_packages(self): |
| 235 | + packages_to_install = {} |
| 236 | + total_size = 0 |
| 237 | + stderr = None |
| 238 | +- tdnf_cmd = "tdnf install --releasever {0} --installroot {1} --assumeyes -c {2} {3}".format( |
| 239 | +- self.install_config['photon_release_version'], self.photon_root, |
| 240 | +- self.tdnf_conf_path, " ".join(selected_packages)) |
| 241 | ++ tdnf_cmd = ("tdnf install -y --releasever {0} --installroot {1} " |
| 242 | ++ "-c {2} --setopt=reposdir={3} " |
| 243 | ++ "{4}").format(self.install_config['photon_release_version'], |
| 244 | ++ self.photon_root, |
| 245 | ++ self.tdnf_conf_path, |
| 246 | ++ self.working_directory, |
| 247 | ++ " ".join(selected_packages)) |
| 248 | + self.logger.debug(tdnf_cmd) |
| 249 | + |
| 250 | + # run in shell to do not throw exception if tdnf not found |
| 251 | +@@ -922,7 +925,7 @@ def _install_packages(self): |
| 252 | + if state == 0: |
| 253 | + if output == 'Installing:\n': |
| 254 | + state = 1 |
| 255 | +- elif state == 1: #N A EVR Size(readable) Size(in bytes) |
| 256 | ++ elif state == 1: # N A EVR Size(readable) Size(in bytes) |
| 257 | + if output == '\n': |
| 258 | + state = 2 |
| 259 | + self.progress_bar.update_num_items(total_size) |
| 260 | +@@ -948,7 +951,7 @@ def _install_packages(self): |
| 261 | + |
| 262 | + self.progress_bar.update_message(output) |
| 263 | + else: |
| 264 | +- stdout,stderr = process.communicate() |
| 265 | ++ stdout, stderr = process.communicate() |
| 266 | + self.logger.info(stdout.decode()) |
| 267 | + retval = process.returncode |
| 268 | + # image creation. host's tdnf might not be available or can be outdated (Photon 1.0) |
| 269 | +@@ -958,9 +961,9 @@ def _install_packages(self): |
| 270 | + stderr = None |
| 271 | + self.logger.info("Retry 'tdnf install' using docker image") |
| 272 | + retval = self.cmd.run(['docker', 'run', |
| 273 | +- '-v', self.rpm_cache_dir+':'+self.rpm_cache_dir, |
| 274 | +- '-v', self.working_directory+':'+self.working_directory, |
| 275 | +- self.install_config['photon_docker_image'], '/bin/sh', '-c', tdnf_cmd]) |
| 276 | ++ '-v', self.rpm_cache_dir+':'+self.rpm_cache_dir, |
| 277 | ++ '-v', self.working_directory+':'+self.working_directory, |
| 278 | ++ self.install_config['photon_docker_image'], '/bin/sh', '-c', tdnf_cmd]) |
| 279 | + |
| 280 | + # 0 : succeed; 137 : package already installed; 65 : package not found in repo. |
| 281 | + if retval != 0 and retval != 137: |
| 282 | +@@ -1036,12 +1039,12 @@ def _create_logical_volumes(self, physical_partition, vg_name, lv_partitions, ex |
| 283 | + """ |
| 284 | + Create logical volumes |
| 285 | + """ |
| 286 | +- #Remove LVM logical volumes and volume groups if already exists |
| 287 | +- #Existing lvs & vg should be removed to continue re-installation |
| 288 | +- #else pvcreate command fails to create physical volumes even if executes forcefully |
| 289 | ++ # Remove LVM logical volumes and volume groups if already exists |
| 290 | ++ # Existing lvs & vg should be removed to continue re-installation |
| 291 | ++ # else pvcreate command fails to create physical volumes even if executes forcefully |
| 292 | + retval = self.cmd.run(['bash', '-c', 'pvs | grep {}'. format(vg_name)]) |
| 293 | + if retval == 0: |
| 294 | +- #Remove LV's associated to VG and VG |
| 295 | ++ # Remove LV's associated to VG and VG |
| 296 | + retval = self.cmd.run(["vgremove", "-f", vg_name]) |
| 297 | + if retval != 0: |
| 298 | + self.logger.error("Error: Failed to remove existing vg before installation {}". format(vg_name)) |
| 299 | +@@ -1071,12 +1074,12 @@ def _create_logical_volumes(self, physical_partition, vg_name, lv_partitions, ex |
| 300 | + lv_cmd = ['lvcreate', '-y'] |
| 301 | + lv_name = partition['lvm']['lv_name'] |
| 302 | + size = partition['size'] |
| 303 | +- if partition['size'] == 0: |
| 304 | ++ if size == 0: |
| 305 | + # Each volume group can have only one extensible logical volume |
| 306 | + if not extensible_logical_volume: |
| 307 | + extensible_logical_volume = partition |
| 308 | + else: |
| 309 | +- lv_cmd.extend(['-L', '{}M'.format(partition['size']), '-n', lv_name, vg_name ]) |
| 310 | ++ lv_cmd.extend(['-L', '{}M'.format(size), '-n', lv_name, vg_name]) |
| 311 | + retval = self.cmd.run(lv_cmd) |
| 312 | + if retval != 0: |
| 313 | + raise Exception("Error: Failed to create logical volumes , command: {}".format(lv_cmd)) |
| 314 | +@@ -1088,7 +1091,7 @@ def _create_logical_volumes(self, physical_partition, vg_name, lv_partitions, ex |
| 315 | + |
| 316 | + lv_name = extensible_logical_volume['lvm']['lv_name'] |
| 317 | + lv_cmd = ['lvcreate', '-y'] |
| 318 | +- lv_cmd.extend(['-l', '100%FREE', '-n', lv_name, vg_name ]) |
| 319 | ++ lv_cmd.extend(['-l', '100%FREE', '-n', lv_name, vg_name]) |
| 320 | + |
| 321 | + retval = self.cmd.run(lv_cmd) |
| 322 | + if retval != 0: |
| 323 | +@@ -1152,7 +1155,7 @@ def _get_partition_tree_view(self): |
| 324 | + |
| 325 | + # Add accumulated VG partitions |
| 326 | + for disk, vg_list in vg_partitions.items(): |
| 327 | +- ptv[disk].extend(vg_list.values()) |
| 328 | ++ ptv[disk].extend(vg_list.values()) |
| 329 | + return ptv |
| 330 | + |
| 331 | + def _insert_boot_partitions(self): |
| 332 | +@@ -1165,7 +1168,7 @@ def _insert_boot_partitions(self): |
| 333 | + if ptype == PartitionType.ESP: |
| 334 | + esp_found = True |
| 335 | + |
| 336 | +- # Adding boot partition required for ostree if already not present in partitions table |
| 337 | ++ # Adding boot partition required for ostree if already not present in partitions table |
| 338 | + if 'ostree' in self.install_config: |
| 339 | + mount_points = [partition['mountpoint'] for partition in self.install_config['partitions'] if 'mountpoint' in partition] |
| 340 | + if '/boot' not in mount_points: |
| 341 | +@@ -1176,12 +1179,12 @@ def _insert_boot_partitions(self): |
| 342 | + |
| 343 | + # Insert efi special partition |
| 344 | + if not esp_found and (bootmode == 'dualboot' or bootmode == 'efi'): |
| 345 | +- efi_partition = { 'size': ESPSIZE, 'filesystem': 'vfat', 'mountpoint': '/boot/efi' } |
| 346 | ++ efi_partition = {'size': ESPSIZE, 'filesystem': 'vfat', 'mountpoint': '/boot/efi'} |
| 347 | + self.install_config['partitions'].insert(0, efi_partition) |
| 348 | + |
| 349 | + # Insert bios partition last to be very first |
| 350 | + if not bios_found and (bootmode == 'dualboot' or bootmode == 'bios'): |
| 351 | +- bios_partition = { 'size': BIOSSIZE, 'filesystem': 'bios' } |
| 352 | ++ bios_partition = {'size': BIOSSIZE, 'filesystem': 'bios'} |
| 353 | + self.install_config['partitions'].insert(0, bios_partition) |
| 354 | + |
| 355 | + def _partition_disk(self): |
| 356 | +@@ -1242,7 +1245,7 @@ def _partition_disk(self): |
| 357 | + # Try to use 'sgdisk -m' to convert GPT to MBR and see whether it works. |
| 358 | + if self.install_config.get('partition_type', 'gpt') == 'msdos': |
| 359 | + # m - colon separated partitions list |
| 360 | +- m = ":".join([str(i) for i in range(1,part_idx)]) |
| 361 | ++ m = ":".join([str(i) for i in range(1, part_idx)]) |
| 362 | + retval = self.cmd.run(['sgdisk', '-m', m, disk]) |
| 363 | + if retval != 0: |
| 364 | + raise Exception("Failed to setup efi partition") |
| 365 | +@@ -1300,7 +1303,7 @@ def _format_partitions(self): |
| 366 | + mkfs_cmd = ['mkfs', '-t', partition['filesystem']] |
| 367 | + |
| 368 | + if 'fs_options' in partition: |
| 369 | +- options = re.sub("[^\S]", " ", partition['fs_options']).split() |
| 370 | ++ options = re.sub(r"[^\S]", " ", partition['fs_options']).split() |
| 371 | + mkfs_cmd.extend(options) |
| 372 | + |
| 373 | + mkfs_cmd.extend([partition['path']]) |
| 374 | +@@ -1309,7 +1312,7 @@ def _format_partitions(self): |
| 375 | + if retval != 0: |
| 376 | + raise Exception( |
| 377 | + "Failed to format {} partition @ {}".format(partition['filesystem'], |
| 378 | +- partition['path'])) |
| 379 | ++ partition['path'])) |
| 380 | + |
| 381 | + def getfile(self, filename): |
| 382 | + """ |
0 commit comments