148 lines
5.1 KiB
Python
Executable File
148 lines
5.1 KiB
Python
Executable File
#! /usr/bin/python3
|
|
#
|
|
#
|
|
# Author: Mahmoud Bassiouny <mbassiouny@vmware.com>
|
|
import os
|
|
import subprocess
|
|
import shlex
|
|
import requests
|
|
import time
|
|
import json
|
|
from argparse import ArgumentParser
|
|
from installer import Installer
|
|
from commandutils import CommandUtils
|
|
from jsonwrapper import JsonWrapper
|
|
|
|
class IsoInstaller(object):
|
|
def __init__(self, options):
|
|
install_config=None
|
|
self.media_mount_path = None
|
|
photon_media = None
|
|
ks_path = options.install_config_file
|
|
# Path to RPMS repository: local media or remote URL
|
|
# If --repo-path= provided - use it,
|
|
# if not provided - use kernel repo= parameter,
|
|
# if not provided - use /RPMS path from photon_media,
|
|
# exit otherwise.
|
|
repo_path = options.repo_path
|
|
|
|
with open('/proc/cmdline', 'r') as f:
|
|
kernel_params = shlex.split(f.read().replace('\n', ''))
|
|
|
|
for arg in kernel_params:
|
|
if arg.startswith("ks="):
|
|
if not ks_path:
|
|
ks_path = arg[len("ks="):]
|
|
elif arg.startswith("repo="):
|
|
if not repo_path:
|
|
repo_path = arg[len("repo="):]
|
|
elif arg.startswith("photon.media="):
|
|
photon_media = arg[len("photon.media="):]
|
|
|
|
if photon_media:
|
|
self.mount_media(photon_media)
|
|
|
|
if not repo_path:
|
|
if self.media_mount_path:
|
|
repo_path = self.media_mount_path + "/RPMS"
|
|
else:
|
|
print("Please specify RPM repo path.")
|
|
return
|
|
|
|
if ks_path:
|
|
install_config=self._load_ks_config(ks_path)
|
|
|
|
if options.ui_config_file:
|
|
ui_config = (JsonWrapper(options.ui_config_file)).read()
|
|
else:
|
|
ui_config={}
|
|
ui_config['options_file'] = options.options_file
|
|
|
|
# Run installer
|
|
installer = Installer(rpm_path=repo_path, log_path="/var/log")
|
|
|
|
installer.configure(install_config, ui_config)
|
|
installer.execute()
|
|
|
|
def _load_ks_config(self, path):
|
|
"""kick start configuration"""
|
|
if path.startswith("http://"):
|
|
# Do 5 trials to get the kick start
|
|
# TODO: make sure the installer run after network is up
|
|
ks_file_error = "Failed to get the kickstart file at {0}".format(path)
|
|
wait = 1
|
|
for _ in range(0, 5):
|
|
err_msg = ""
|
|
try:
|
|
response = requests.get(path, timeout=3)
|
|
if response.ok:
|
|
return json.loads(response.text)
|
|
err_msg = response.text
|
|
except Exception as e:
|
|
err_msg = e
|
|
|
|
print(ks_file_error)
|
|
print("error msg: {0}".format(err_msg))
|
|
print("retry in a second")
|
|
time.sleep(wait)
|
|
wait = wait * 2
|
|
|
|
# Something went wrong
|
|
print(ks_file_error)
|
|
raise Exception(err_msg)
|
|
else:
|
|
if path.startswith("cdrom:/"):
|
|
if self.media_mount_path is None:
|
|
raise Exception("cannot read ks config from cdrom, no cdrom specified")
|
|
path = os.path.join(self.media_mount_path, path.replace("cdrom:/", "", 1))
|
|
return (JsonWrapper(path)).read()
|
|
|
|
def mount_media(self, photon_media):
|
|
"""Mount the cd with RPMS"""
|
|
# check if the cd is already mounted
|
|
if self.media_mount_path:
|
|
return
|
|
mount_path = "/mnt/media"
|
|
|
|
# Mount the cd to get the RPMS
|
|
os.makedirs(mount_path, exist_ok=True)
|
|
|
|
# Construct mount cmdline
|
|
cmdline = ['mount']
|
|
if photon_media.startswith("UUID="):
|
|
cmdline.extend(['-U', photon_media[len("UUID="):] ])
|
|
elif photon_media.startswith("LABEL="):
|
|
cmdline.extend(['-L', photon_media[len("LABEL="):] ])
|
|
elif photon_media == "cdrom":
|
|
cmdline.append('/dev/cdrom')
|
|
else:
|
|
print("Unsupported installer media, check photon.media in kernel cmdline")
|
|
raise Exception("Can not mount the cd")
|
|
|
|
cmdline.extend(['-o', 'ro', mount_path])
|
|
|
|
# Retry mount the CD
|
|
for _ in range(0, 3):
|
|
process = subprocess.Popen(cmdline)
|
|
retval = process.wait()
|
|
if retval == 0:
|
|
self.media_mount_path = mount_path
|
|
return
|
|
print("Failed to mount the cd, retry in a second")
|
|
time.sleep(1)
|
|
print("Failed to mount the cd, exiting the installer")
|
|
print("check the logs for more details")
|
|
raise Exception("Can not mount the cd")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
usage = "Usage: %prog [options]"
|
|
parser = ArgumentParser(usage)
|
|
parser.add_argument("-c", "--config", dest="install_config_file")
|
|
parser.add_argument("-u", "--ui-config", dest="ui_config_file")
|
|
parser.add_argument("-j", "--json-file", dest="options_file", default="input.json")
|
|
parser.add_argument("-r", "--repo-path", dest="repo_path")
|
|
options = parser.parse_args()
|
|
|
|
IsoInstaller(options)
|