#! /usr/bin/python2
#
# Copyright (C) 2015 vmware inc.
#
# Author: Mahmoud Bassiouny <mbassiouny@vmware.com>
from optparse import OptionParser
from installer import Installer
import crypt
import random
import string
import subprocess
import sys
import os
from jsonwrapper import JsonWrapper
from packageselector import PackageSelector
import json
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 partition_disk(disk):
partitions_data = {}
partitions_data['disk'] = disk
partitions_data['root'] = disk + '2'
partitions_data['swap'] = disk + '3'
# Clear the disk
process = subprocess.Popen(['sgdisk', '-z', partitions_data['disk']])
retval = process.wait()
# 1: grub, 2: swap, 3: filesystem
process = subprocess.Popen(['sgdisk', '-n', '1::+2M', '-n', '3:-3G:', '-n', '2:', '-p', partitions_data['disk']])
retval = process.wait()
# Add the grub flags
process = subprocess.Popen(['sgdisk', '-t1:ef02', partitions_data['disk']])
retval = process.wait()
# format the swap
process = subprocess.Popen(['mkswap', partitions_data['swap']])
retval = process.wait()
# format the file system
process = subprocess.Popen(['mkfs', '-t', 'ext4', partitions_data['root']])
retval = process.wait()
return partitions_data
def create_vmdk_and_partition(config, vmdk_path):
partitions_data = {}
process = subprocess.Popen(['./mk-setup-vmdk.sh', '-rp', config['size']['root'], '-sp', config['size']['swap'], '-n', vmdk_path, '-m'], stdout=subprocess.PIPE)
count = 0
for line in iter(process.stdout.readline, ''):
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()
partitions_data['boot'] = partitions_data['root']
partitions_data['bootdirectory'] = '/boot/'
count += 1
if count == 2:
partitions_data['partitions'] = [{'path': partitions_data['root'], 'mountpoint': '/', 'filesystem': 'ext4'}]
return partitions_data, count == 2
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):
json_wrapper_option_list = JsonWrapper(build_install_option)
option_list_json = json_wrapper_option_list.read()
options_sorted = option_list_json.items()
packages = []
for install_option in options_sorted:
if install_option[0] != "iso":
file_path = os.path.join(output_data_path, install_option[1]["file"])
json_wrapper_package_list = JsonWrapper(file_path)
package_list_json = json_wrapper_package_list.read()
packages = packages + package_list_json["packages"]
return packages
#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
def create_rpm_list_to_be_copied_to_iso(pkg_to_rpm_map_file, build_install_option, copy_flags, output_data_path):
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']
rpm_list.append(pkg_to_rpm_map[k]['debugrpm'])
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
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:
if install_option[1].has_key("additional-files"):
file_list = file_list + map(lambda filename: os.path.join(base_path, filename), install_option[1].get("additional-files"))
return file_list
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:
if install_option[1].has_key("live-cd"):
if install_option[1].get("live-cd") == True:
return "true"
return "false"
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()
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()
if __name__ == '__main__':
usage = "Usage: %prog [options] <config file> <tools path>"
parser = OptionParser(usage)
parser.add_option("-i", "--iso-path", dest="iso_path")
parser.add_option("-j", "--src-iso-path", dest="src_iso_path")
parser.add_option("-k", "--debug-iso-path", dest="debug_iso_path")
parser.add_option("-v", "--vmdk-path", dest="vmdk_path")
parser.add_option("-w", "--working-directory", dest="working_directory", default="/mnt/photon-root")
parser.add_option("-l", "--log-path", dest="log_path", default="../stage/LOGS")
parser.add_option("-r", "--rpm-path", dest="rpm_path", default="../stage/RPMS")
parser.add_option("-x", "--srpm-path", dest="srpm_path", default="../stage/SRPMS")
parser.add_option("-o", "--output-data-path", dest="output_data_path", default="../stage/common/data/")
parser.add_option("-f", "--force", action="store_true", dest="force", default=False)
parser.add_option("-p", "--package-list-file", dest="package_list_file", default="../common/data/build_install_options_all.json")
parser.add_option("-m", "--stage-path", dest="stage_path", default="../stage")
parser.add_option("-s", "--json-data-path", dest="json_data_path", default="../stage/common/data/")
parser.add_option("-d", "--pkg-to-rpm-map-file", dest="pkg_to_rpm_map_file", default="../stage/pkg_info.json")
parser.add_option("-c", "--pkg-to-be-copied-conf-file", dest="pkg_to_be_copied_conf_file")
(options, args) = parser.parse_args()
# Cleanup the working directory
if not options.force:
proceed = query_yes_no("This will remove everything under {0}. Are you sure?".format(options.working_directory))
if not proceed:
sys.exit(0)
if options.src_iso_path:
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)
make_src_iso(options.working_directory, options.src_iso_path, rpm_list)
else:
if options.iso_path:
# Check the arguments
if (len(args)) != 0:
parser.error("Incorrect arguments")
config = {}
config['iso_system'] = True
config['vmdk_install'] = False
config['type'] = 'iso'
elif options.vmdk_path:
# Check the arguments
if (len(args)) != 1:
parser.error("Incorrect arguments")
# Read the conf file
config = (JsonWrapper(args[0])).read()
config['disk'], success = create_vmdk_and_partition(config, options.vmdk_path)
if not success:
print "Unexpected failure, please check the logs"
sys.exit(1)
config['iso_system'] = False
config['vmdk_install'] = True
else:
# Check the arguments
if (len(args)) != 1:
parser.error("Incorrect arguments")
# Read the conf file
config = (JsonWrapper(args[0])).read()
config['iso_system'] = False
config['vmdk_install'] = False
config["pkg_to_rpm_map_file"] = options.pkg_to_rpm_map_file
if 'password' in config:
# crypt the password if needed
if config['password']['crypted']:
config['password'] = config['password']['text']
else:
config['password'] = crypt.crypt(config['password']['text'], "$6$" + "".join([random.choice(string.ascii_letters + string.digits) for _ in range(16)]))
# 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()
packages = []
packages = PackageSelector.get_packages_to_install(options_sorted, config['type'], options.output_data_path)
config['packages'] = packages
if (os.path.isdir(options.working_directory)):
process = subprocess.Popen(['rm', '-rf', options.working_directory])
retval = process.wait()
process = subprocess.Popen(['mkdir', '-p', os.path.join(options.working_directory, "photon-chroot")])
retval = process.wait()
config['working_directory'] = options.working_directory
# Run the installer
package_installer = Installer(config, rpm_path = options.rpm_path, log_path = options.log_path)
package_installer.install(None)
# Making the iso if needed
if options.iso_path:
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))
live_cd = get_live_cd_status_string(options.package_list_file)
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])
retval = process.wait()
if options.debug_iso_path:
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)
make_debug_iso(options.working_directory, options.debug_iso_path, debug_rpm_list)
# 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
if (options.iso_path or options.vmdk_path or options.debug_iso_path):
process = subprocess.Popen(['rm', '-rf', options.working_directory])
retval = process.wait()