installer/photonInstaller.py
14d32ad2
 #! /usr/bin/python3
f4d17450
 #
 #    Copyright (C) 2015 vmware inc.
 #
 #    Author: Mahmoud Bassiouny <mbassiouny@vmware.com>
 
0f3948ba
 from argparse import ArgumentParser
f4d17450
 from installer import Installer
 import crypt
 import random
 import string
 import subprocess
 import sys
 import os
 from jsonwrapper import JsonWrapper
bb884b5b
 from packageselector import PackageSelector
f4d17450
 
 def query_yes_no(question, default="no"):
     valid = {"yes": True, "y": True, "ye": True,
              "no": False, "n": False}
     if default is None:
         prompt = " [y/n] "
     elif default == "yes":
         prompt = " [Y/n] "
     elif default == "no":
         prompt = " [y/N] "
     else:
         raise ValueError("invalid default answer: '%s'" % default)
 
     while True:
         sys.stdout.write(question + prompt)
         choice = raw_input().lower().strip()
         if default is not None and choice == '':
             return valid[default]
         elif choice in valid:
             return valid[choice]
         else:
             sys.stdout.write("Please respond with 'yes' or 'no' "
                              "(or 'y' or 'n').\n")
 
 def create_vmdk_and_partition(config, vmdk_path):
     partitions_data = {}
628381b8
 
33a3c5ac
     firmware = "bios"
     if 'boot' in config and config['boot'] == 'efi':
         firmware = "efi"
14d32ad2
     process = subprocess.Popen(['./mk-setup-vmdk.sh', '-rp', config['size']['root'], '-sp',
                                 config['size']['swap'], '-n', vmdk_path, '-fm', firmware, '-m'],
                                stdout=subprocess.PIPE)
f4d17450
     count = 0
628381b8
 
     while True:
         line = process.stdout.readline().decode()
         if line == '':
             retval = process.poll()
             if retval is not None:
                 break
f4d17450
         sys.stdout.write(line)
         if line.startswith("DISK_DEVICE="):
             partitions_data['disk'] = line.replace("DISK_DEVICE=", "").strip()
             count += 1
         elif line.startswith("ROOT_PARTITION="):
             partitions_data['root'] = line.replace("ROOT_PARTITION=", "").strip()
c3771c35
             partitions_data['boot'] = partitions_data['root']
             partitions_data['bootdirectory'] = '/boot/'
f4d17450
             count += 1
5d05cfcc
 
c3771c35
     if count == 2:
14d32ad2
         partitions_data['partitions'] = [{'path': partitions_data['root'], 'mountpoint': '/',
                                           'filesystem': 'ext4'}]
c3771c35
 
f4d17450
     return partitions_data, count == 2
5d05cfcc
 
eccee406
 def get_file_name_with_last_folder(filename):
     basename = os.path.basename(filename)
     dirname = os.path.dirname(filename)
     lastfolder = os.path.basename(dirname)
     name = os.path.join(lastfolder, basename)
     return name
 def create_pkg_list_to_copy_to_iso(build_install_option, output_data_path):
4d6a578d
     json_wrapper_option_list = JsonWrapper(build_install_option)
     option_list_json = json_wrapper_option_list.read()
dc0dfc30
     options_sorted = option_list_json.items()
4d6a578d
     packages = []
     for install_option in options_sorted:
07751fba
         if install_option[0] != "iso":
2cbd5a80
             file_path = os.path.join(output_data_path, install_option[1]["file"])
07751fba
             json_wrapper_package_list = JsonWrapper(file_path)
             package_list_json = json_wrapper_package_list.read()
             packages = packages + package_list_json["packages"]
4d6a578d
     return packages
f4d17450
 
eccee406
     #copy_flags 1: add the rpm file for the package
     #           2: add debuginfo rpm file for the package.
     #           4: add src rpm file for the package
14d32ad2
 def create_rpm_list_to_be_copied_to_iso(pkg_to_rpm_map_file, build_install_option, copy_flags,
                                         output_data_path):
eccee406
     packages = []
     if build_install_option is None:
         packages = []
     else:
         packages = create_pkg_list_to_copy_to_iso(build_install_option, output_data_path)
 
     rpm_list = []
     json_pkg_to_rpm_map = JsonWrapper(pkg_to_rpm_map_file)
     pkg_to_rpm_map = json_pkg_to_rpm_map.read()
     for k in pkg_to_rpm_map:
         if build_install_option is None or k in packages:
             if not pkg_to_rpm_map[k]['rpm'] is None and bool(copy_flags & 1):
                 filename = pkg_to_rpm_map[k]['rpm']
                 rpm_list.append(get_file_name_with_last_folder(filename))
             if not pkg_to_rpm_map[k]['debugrpm'] is None and bool(copy_flags & 2):
                 filename = pkg_to_rpm_map[k]['debugrpm']
7874af21
                 rpm_list.append(pkg_to_rpm_map[k]['debugrpm'])
eccee406
             if not pkg_to_rpm_map[k]['sourcerpm'] is None and bool(copy_flags & 4):
                 rpm_list.append(pkg_to_rpm_map[k]['sourcerpm'])
     return rpm_list
 
2f46569e
 def create_additional_file_list_to_copy_in_iso(base_path, build_install_option):
     json_wrapper_option_list = JsonWrapper(build_install_option)
     option_list_json = json_wrapper_option_list.read()
     options_sorted = option_list_json.items()
     file_list = []
     for install_option in options_sorted:
0c250142
         if "additional-files" in install_option[1]:
14d32ad2
             file_list = file_list + list(map(
                 lambda filename: os.path.join(base_path, filename),
                 install_option[1].get("additional-files")))
2f46569e
     return file_list
 
07751fba
 def get_live_cd_status_string(build_install_option):
     json_wrapper_option_list = JsonWrapper(build_install_option)
     option_list_json = json_wrapper_option_list.read()
     options_sorted = option_list_json.items()
     file_list = []
     for install_option in options_sorted:
0c250142
         if "live-cd" in install_option[1]:
07751fba
             if install_option[1].get("live-cd") == True:
                 return "true"
     return "false"
 
eccee406
 def make_src_iso(working_directory, src_iso_path, rpm_list):
     if os.path.isdir(working_directory):
         process = subprocess.Popen(['rm', '-rf', working_directory])
         retval = process.wait()
     process = subprocess.Popen(['mkdir', '-p', os.path.join(working_directory, "SRPMS")])
     retval = process.wait()
     for aaa in rpm_list:
         if os.path.isfile(aaa):
             process = subprocess.Popen(['cp', aaa, os.path.join(working_directory, "SRPMS")])
             retval = process.wait()
     process = subprocess.Popen(['mkisofs', '-r', '-o', src_iso_path, working_directory])
     retval = process.wait()
     process = subprocess.Popen(['rm', '-rf', options.working_directory])
     retval = process.wait()
 
7874af21
 def make_debug_iso(working_directory, debug_iso_path, rpm_list):
     if os.path.isdir(working_directory):
         process = subprocess.Popen(['rm', '-rf', working_directory])
         retval = process.wait()
     process = subprocess.Popen(['mkdir', '-p', os.path.join(working_directory, "DEBUGRPMS")])
     retval = process.wait()
     for aaa in rpm_list:
         if os.path.isfile(aaa):
             dirname = os.path.dirname(aaa)
             lastfolder = os.path.basename(dirname)
             dest_working_directory = os.path.join(working_directory, "DEBUGRPMS", lastfolder)
             if not os.path.isdir(dest_working_directory):
                 process = subprocess.Popen(['mkdir', dest_working_directory])
                 retval = process.wait()
             process = subprocess.Popen(['cp', aaa, dest_working_directory])
             retval = process.wait()
     process = subprocess.Popen(['mkisofs', '-r', '-o', debug_iso_path, working_directory])
     retval = process.wait()
     process = subprocess.Popen(['rm', '-rf', options.working_directory])
     retval = process.wait()
 
f4d17450
 if __name__ == '__main__':
     usage = "Usage: %prog [options] <config file> <tools path>"
0f3948ba
     parser = ArgumentParser(usage)
14d32ad2
     parser.add_argument("-i", "--iso-path", dest="iso_path")
     parser.add_argument("-j", "--src-iso-path", dest="src_iso_path")
     parser.add_argument("-k", "--debug-iso-path", dest="debug_iso_path")
0f3948ba
     parser.add_argument("-v", "--vmdk-path", dest="vmdk_path")
14d32ad2
     parser.add_argument("-w", "--working-directory", dest="working_directory",
                         default="/mnt/photon-root")
     parser.add_argument("-l", "--log-path", dest="log_path",
                         default="../stage/LOGS")
     parser.add_argument("-r", "--rpm-path", dest="rpm_path", default="../stage/RPMS")
     parser.add_argument("-x", "--srpm-path", dest="srpm_path", default="../stage/SRPMS")
     parser.add_argument("-o", "--output-data-path", dest="output_data_path",
                         default="../stage/common/data/")
0f3948ba
     parser.add_argument("-f", "--force", action="store_true", dest="force", default=False)
14d32ad2
     parser.add_argument("-p", "--package-list-file", dest="package_list_file",
                         default="../common/data/build_install_options_all.json")
0f3948ba
     parser.add_argument("-m", "--stage-path", dest="stage_path", default="../stage")
14d32ad2
     parser.add_argument("-s", "--json-data-path", dest="json_data_path",
                         default="../stage/common/data/")
     parser.add_argument("-d", "--pkg-to-rpm-map-file", dest="pkg_to_rpm_map_file",
                         default="../stage/pkg_info.json")
0f3948ba
     parser.add_argument("-c", "--pkg-to-be-copied-conf-file", dest="pkg_to_be_copied_conf_file")
     parser.add_argument('configfile', nargs='?')
     options = parser.parse_args()
eccee406
     # Cleanup the working directory
     if not options.force:
14d32ad2
         proceed = query_yes_no("This will remove everything under {0}. " +
                                "Are you sure?".format(options.working_directory))
eccee406
         if not proceed:
             sys.exit(0)
f4d17450
 
eccee406
     if options.src_iso_path:
14d32ad2
         rpm_list = create_rpm_list_to_be_copied_to_iso(options.pkg_to_rpm_map_file,
                                                        options.pkg_to_be_copied_conf_file, 4,
                                                        options.output_data_path)
eccee406
         make_src_iso(options.working_directory, options.src_iso_path, rpm_list)
f4d17450
 
eccee406
     else:
         if options.iso_path:
             # Check the arguments
0f3948ba
             if options.configfile:
eccee406
                 parser.error("Incorrect arguments")
             config = {}
             config['iso_system'] = True
             config['vmdk_install'] = False
             config['type'] = 'iso'
 
         elif options.vmdk_path:
             # Check the arguments
0f3948ba
             if not options.configfile:
eccee406
                 parser.error("Incorrect arguments")
 
             # Read the conf file
0f3948ba
             config = (JsonWrapper(options.configfile)).read()
eccee406
             config['disk'], success = create_vmdk_and_partition(config, options.vmdk_path)
             if not success:
0c250142
                 print("Unexpected failure, please check the logs")
eccee406
                 sys.exit(1)
 
             config['iso_system'] = False
             config['vmdk_install'] = True
f4d17450
         else:
eccee406
             # Check the arguments
0f3948ba
             if not options.configfile:
eccee406
                 parser.error("Incorrect arguments")
f4d17450
 
eccee406
             # Read the conf file
0f3948ba
             config = (JsonWrapper(options.configfile)).read()
bb884b5b
 
eccee406
             config['iso_system'] = False
             config['vmdk_install'] = False
4d6a578d
 
b944098f
         config["pkg_to_rpm_map_file"] = options.pkg_to_rpm_map_file
628381b8
 
eccee406
         if 'password' in config:
             # crypt the password if needed
             if config['password']['crypted']:
                 config['password'] = config['password']['text']
             else:
14d32ad2
                 config['password'] = crypt.crypt(
                     config['password']['text'],
                     "$6$" + "".join([random.choice(
                         string.ascii_letters + string.digits) for _ in range(16)]))
f4d17450
 
eccee406
         # Check the installation type
         json_wrapper_option_list = JsonWrapper(options.package_list_file)
         option_list_json = json_wrapper_option_list.read()
         options_sorted = option_list_json.items()
57342c05
 
eccee406
         packages = []
14d32ad2
         packages = PackageSelector.get_packages_to_install(options_sorted, config['type'],
                                                            options.output_data_path)
f4d17450
 
eccee406
         config['packages'] = packages
f4d17450
 
14d32ad2
         if os.path.isdir(options.working_directory):
eccee406
             process = subprocess.Popen(['rm', '-rf', options.working_directory])
             retval = process.wait()
f4d17450
 
14d32ad2
         process = subprocess.Popen(['mkdir', '-p',
                                     os.path.join(options.working_directory, "photon-chroot")])
f4d17450
         retval = process.wait()
 
eccee406
         config['working_directory'] = options.working_directory
 
         # Run the installer
14d32ad2
         package_installer = Installer(config, rpm_path=options.rpm_path,
                                       log_path=options.log_path)
eccee406
         package_installer.install(None)
 
         # Making the iso if needed
         if options.iso_path:
14d32ad2
             rpm_list = " ".join(
                 create_rpm_list_to_be_copied_to_iso(
                     options.pkg_to_rpm_map_file,
                     options.pkg_to_be_copied_conf_file, 1, options.output_data_path))
             files_to_copy = " ".join(
                 create_additional_file_list_to_copy_in_iso(
                     os.path.abspath(options.stage_path), options.package_list_file))
 
eccee406
             live_cd = get_live_cd_status_string(options.package_list_file)
14d32ad2
             process = subprocess.Popen(['./mk-install-iso.sh', '-w',
                                         options.working_directory, options.iso_path,
                                         options.rpm_path, options.package_list_file,
                                         rpm_list, options.stage_path, files_to_copy,
                                         live_cd, options.json_data_path])
eccee406
             retval = process.wait()
 
7874af21
         if options.debug_iso_path:
14d32ad2
             debug_rpm_list = create_rpm_list_to_be_copied_to_iso(
                 options.pkg_to_rpm_map_file, options.pkg_to_be_copied_conf_file, 2,
                 options.output_data_path)
7874af21
             make_debug_iso(options.working_directory, options.debug_iso_path, debug_rpm_list)
 
eccee406
         # Cleaning up for vmdk
         if 'vmdk_install' in config and config['vmdk_install']:
             process = subprocess.Popen(['./mk-clean-vmdk.sh', config['disk']['disk']])
             process.wait()
 
         #Clean up the working directories
14d32ad2
         if options.iso_path or options.vmdk_path or options.debug_iso_path:
eccee406
             process = subprocess.Popen(['rm', '-rf', options.working_directory])
             retval = process.wait()