Skip to content

Commit f6de4c2

Browse files
committed
photon-os-installer: fix tdnf installroot commands
Change-Id: I38b792b77c13a99b7d8bdc174919dd6c48227dc2 Signed-off-by: Shreenidhi Shedi <[email protected]> Reviewed-on: http://photon-jenkins.eng.vmware.com:8082/14961 Reviewed-by: Ankit Jain <[email protected]> Tested-by: gerrit-photon <[email protected]>
1 parent d71ff2b commit f6de4c2

File tree

2 files changed

+386
-1
lines changed

2 files changed

+386
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,382 @@
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

Comments
 (0)