039cb7bb |
#!/usr/bin/python3 |
8ff5c437 |
import os
import re
import shutil
import tarfile
import fileinput |
039cb7bb |
from argparse import ArgumentParser |
64ead533 |
import json |
039cb7bb |
from utils import Utils |
8ff5c437 |
def create_ova_image(raw_image_name, tools_path, build_scripts_path, config):
output_path = os.path.dirname(os.path.realpath(raw_image_name))
utils = Utils()
# Remove older artifacts |
64ead533 |
files = os.listdir(output_path) |
8ff5c437 |
for file in files: |
e7b64224 |
if file.endswith(".vmdk"): |
8ff5c437 |
os.remove(os.path.join(output_path, file))
vmx_path = output_path + '/photon-ova.vmx' |
039cb7bb |
utils.replaceandsaveasnewfile(build_scripts_path + '/vmx-template',
vmx_path, 'VMDK_IMAGE',
output_path + '/photon-ova.vmdk') |
8ff5c437 |
vixdiskutil_path = tools_path + 'vixdiskutil'
vmdk_path = output_path + '/photon-ova.vmdk'
ovf_path = output_path + '/photon-ova.ovf'
mf_path = output_path + '/photon-ova.mf' |
3b85c978 |
ovfinfo_path = build_scripts_path + '/ovfinfo.txt' |
039cb7bb |
vmdk_capacity = (int(config['size']['root']) +
int(config['size']['swap'])) * 1024
utils.runshellcommand(
"{} -convert {} -cap {} {}".format(vixdiskutil_path,
raw_image_name,
vmdk_capacity,
vmdk_path))
utils.runshellcommand(
"{} -wmeta toolsVersion 2147483647 {}".format(vixdiskutil_path, vmdk_path)) |
8ff5c437 |
utils.runshellcommand("ovftool {} {}".format(vmx_path, ovf_path))
utils.replaceinfile(ovf_path, 'otherGuest', 'other3xLinux64Guest')
#Add product info |
3b85c978 |
if os.path.exists(ovfinfo_path):
with open(ovfinfo_path) as f:
lines = f.readlines()
for line in fileinput.input(ovf_path, inplace=True): |
40e72bb6 |
if line.strip() == '</VirtualHardwareSection>': |
3b85c978 |
for ovfinfoline in lines: |
039cb7bb |
print(ovfinfoline) |
40e72bb6 |
else: |
039cb7bb |
print(line) |
8ff5c437 |
if os.path.exists(mf_path):
os.remove(mf_path)
cwd = os.getcwd()
os.chdir(output_path)
out = utils.runshellcommand("openssl sha1 photon-ova-disk1.vmdk photon-ova.ovf")
with open(mf_path, "w") as source:
source.write(out)
rawsplit = os.path.splitext(raw_image_name)
ova_name = rawsplit[0] + '.ova'
|
039cb7bb |
ovatar = tarfile.open(ova_name, "w", format=tarfile.USTAR_FORMAT) |
8ff5c437 |
for name in ["photon-ova.ovf", "photon-ova.mf", "photon-ova-disk1.vmdk"]:
ovatar.add(name, arcname=os.path.basename(name))
ovatar.close() |
64ead533 |
os.remove(vmx_path) |
8ff5c437 |
os.remove(mf_path)
if 'additionalhwversion' in config:
for addlversion in config['additionalhwversion']: |
e7b64224 |
new_ovf_path = output_path + "/photon-ova-hw{}.ovf".format(addlversion)
mf_path = output_path + "/photon-ova-hw{}.mf".format(addlversion) |
039cb7bb |
utils.replaceandsaveasnewfile(
ovf_path, new_ovf_path, "vmx-.*<", "vmx-{}<".format(addlversion))
out = utils.runshellcommand("openssl sha1 photon-ova-disk1.vmdk "
"photon-ova-hw{}.ovf".format(addlversion)) |
8ff5c437 |
with open(mf_path, "w") as source:
source.write(out)
temp_name_list = os.path.basename(ova_name).split('-')
temp_name_list = temp_name_list[:2] + ["hw{}".format(addlversion)] + temp_name_list[2:]
new_ova_name = '-'.join(temp_name_list) |
e7b64224 |
new_ova_path = output_path + '/' + new_ova_name |
039cb7bb |
ovatar = tarfile.open(new_ova_path, "w", format=tarfile.USTAR_FORMAT) |
8ff5c437 |
for name in [new_ovf_path, mf_path, "photon-ova-disk1.vmdk"]:
ovatar.add(name, arcname=os.path.basename(name))
ovatar.close()
os.remove(new_ovf_path)
os.remove(mf_path) |
64ead533 |
os.chdir(cwd) |
8ff5c437 |
os.remove(ovf_path)
os.remove(vmdk_path) |
64ead533 |
files = os.listdir(output_path) |
e7b64224 |
for file in files:
if file.endswith(".vmdk"): |
64ead533 |
os.remove(os.path.join(output_path, file)) |
8ff5c437 |
if __name__ == '__main__':
usage = "Usage: %prog [options]" |
039cb7bb |
parser = ArgumentParser(usage)
parser.add_argument("-r", "--raw-image-path", dest="raw_image_path")
parser.add_argument("-c", "--vmdk-config-path", dest="vmdk_config_path")
parser.add_argument("-w", "--working-directory", dest="working_directory")
parser.add_argument("-m", "--mount-path", dest="mount_path")
parser.add_argument("-a", "--additional-rpms-path", dest="additional_rpms_path")
parser.add_argument("-i", "--image-name", dest="image_name")
parser.add_argument("-t", "--tools-bin-path", dest="tools_bin_path")
parser.add_argument("-b", "--build-scripts-path", dest="build_scripts_path")
parser.add_argument("-s", "--src-root", dest="src_root")
options = parser.parse_args() |
8ff5c437 |
utils = Utils()
config = utils.jsonread(options.vmdk_config_path) |
039cb7bb |
print(options) |
8ff5c437 |
|
039cb7bb |
disk_device = (utils.runshellcommand(
"losetup --show -f {}".format(options.raw_image_path))).rstrip('\n') |
8ff5c437 |
disk_partitions = utils.runshellcommand("kpartx -as {}".format(disk_device))
device_name = disk_device.split('/')[2]
if not os.path.exists(options.mount_path):
os.mkdir(options.mount_path) |
039cb7bb |
loop_device_path = "/dev/mapper/{}p2".format(device_name) |
8ff5c437 |
try: |
039cb7bb |
print("Generating PARTUUID for the loop device ...")
partuuidval = (utils.runshellcommand(
"blkid -s PARTUUID -o value {}".format(loop_device_path))).rstrip('\n')
uuidval = (utils.runshellcommand(
"blkid -s UUID -o value {}".format(loop_device_path))).rstrip('\n')
if partuuidval == '':
sgdiskout = utils.runshellcommand(
"sgdisk -i 2 {} ".format(disk_device))
partuuidval = (re.findall(r'Partition unique GUID.*',
sgdiskout))[0].split(':')[1].strip(' ').lower()
if partuuidval == '': |
8ff5c437 |
raise RuntimeError("Cannot generate partuuid")
# Mount the loop device |
039cb7bb |
print("Mounting the loop device for customization ...")
utils.runshellcommand(
"mount -t ext4 {} {}".format(loop_device_path, options.mount_path)) |
8ff5c437 |
shutil.rmtree(options.mount_path + "/installer", ignore_errors=True)
shutil.rmtree(options.mount_path + "/LOGS", ignore_errors=True)
# Clear the root password if not set explicitly from the config file |
039cb7bb |
if config['password']['text'] != 'PASSWORD':
utils.replaceinfile(options.mount_path + "/etc/shadow",
'root:.*?:', 'root:*:') |
8ff5c437 |
# Clear machine-id so it gets regenerated on boot
open(options.mount_path + "/etc/machine-id", "w").close()
os.remove(options.mount_path + "/etc/fstab")
f = open(options.mount_path + "/etc/fstab", "w") |
039cb7bb |
if uuidval != '': |
d60ce58d |
f.write("UUID={} / ext4 defaults 1 1\n".format(uuidval))
else:
f.write("PARTUUID={} / ext4 defaults 1 1\n".format(partuuidval)) |
8ff5c437 |
f.close() |
039cb7bb |
utils.replaceinfile(options.mount_path + "/boot/grub/grub.cfg",
"rootpartition=PARTUUID=.*$",
"rootpartition=PARTUUID={}".format(partuuidval)) |
8ff5c437 |
if os.path.exists(options.additional_rpms_path): |
039cb7bb |
print("Installing additional rpms") |
8ff5c437 |
os.mkdir(options.mount_path + "/additional_rpms")
os.mkdir(options.mount_path + "/var/run") |
039cb7bb |
utils.copyallfiles(options.additional_rpms_path,
options.mount_path + "/additional_rpms")
utils.runshellcommand(
"chroot {} /bin/bash -c 'rpm -i /additional_rpms/*'".format(options.mount_path)) |
8ff5c437 |
shutil.rmtree(options.mount_path + "/additional_rpms", ignore_errors=True) |
039cb7bb |
shutil.rmtree(options.additional_rpms_path, ignore_errors=True) |
8ff5c437 |
utils.runshellcommand("mount -o bind /proc {}".format(options.mount_path + "/proc")) |
10d18a45 |
utils.runshellcommand("mount -o bind /dev {}".format(options.mount_path + "/dev"))
utils.runshellcommand("mount -o bind /dev/pts {}".format(options.mount_path + "/dev/pts")) |
8ff5c437 |
utils.runshellcommand("mount -o bind /sys {}".format(options.mount_path + "/sys"))
if 'additionalfiles' in config: |
039cb7bb |
print(" Copying additional files into the raw image ...") |
8ff5c437 |
for filetuples in config['additionalfiles']: |
039cb7bb |
for src, dest in filetuples.items():
if (os.path.isdir(options.build_scripts_path + '/' +
options.image_name + '/' + src)):
shutil.copytree(options.build_scripts_path + '/' +
options.image_name + '/' + src,
options.mount_path + dest, True) |
9b9c0eac |
else: |
039cb7bb |
shutil.copyfile(options.build_scripts_path + '/' +
options.image_name + '/' + src,
options.mount_path + dest) |
8ff5c437 |
if 'postinstallscripts' in config: |
039cb7bb |
print(" Running post install scripts ...") |
8ff5c437 |
if not os.path.exists(options.mount_path + "/tempscripts"):
os.mkdir(options.mount_path + "/tempscripts")
for script in config['postinstallscripts']: |
039cb7bb |
shutil.copy(options.build_scripts_path + '/' +
options.image_name + '/' + script,
options.mount_path + "/tempscripts") |
8ff5c437 |
for script in os.listdir(options.mount_path + "/tempscripts"): |
039cb7bb |
print(" ...running script {}".format(script))
utils.runshellcommand(
"chroot {} /bin/bash -c '/tempscripts/{}'".format(options.mount_path, script)) |
8ff5c437 |
shutil.rmtree(options.mount_path + "/tempscripts", ignore_errors=True)
|
9b9c0eac |
except Exception as e: |
039cb7bb |
print(e) |
9b9c0eac |
finally: |
8ff5c437 |
utils.runshellcommand("umount -l {}".format(options.mount_path + "/sys")) |
10d18a45 |
utils.runshellcommand("umount -l {}".format(options.mount_path + "/dev/pts"))
utils.runshellcommand("umount -l {}".format(options.mount_path + "/dev")) |
8ff5c437 |
utils.runshellcommand("umount -l {}".format(options.mount_path + "/proc")) |
9b9c0eac |
utils.runshellcommand("sync") |
8ff5c437 |
utils.runshellcommand("umount -l {}".format(options.mount_path))
|
c061ff83 |
mount_out = utils.runshellcommand("mount") |
039cb7bb |
print("List of mounted devices:")
print(mount_out) |
c061ff83 |
|
8ff5c437 |
utils.runshellcommand("kpartx -d {}".format(disk_device))
utils.runshellcommand("losetup -d {}".format(disk_device))
shutil.rmtree(options.mount_path)
photon_release_ver = os.environ['PHOTON_RELEASE_VER']
photon_build_num = os.environ['PHOTON_BUILD_NUM']
raw_image = options.raw_image_path
new_name = ""
img_path = os.path.dirname(os.path.realpath(raw_image))
# Rename gce image to disk.raw
if options.image_name == "gce": |
039cb7bb |
print("Renaming the raw file to disk.raw ...") |
8ff5c437 |
new_name = img_path + '/disk.raw'
else: |
039cb7bb |
new_name = (img_path + '/photon-' + options.image_name +
'-' + photon_release_ver + '-' +
photon_build_num + '.raw') |
8ff5c437 |
shutil.move(raw_image, new_name)
raw_image = new_name
if config['artifacttype'] == 'tgz': |
039cb7bb |
print("Generating the tar.gz artifact ...")
tarname = (img_path + '/photon-' + options.image_name +
'-' + photon_release_ver + '-' +
photon_build_num + '.tar.gz')
|
c061ff83 |
tgzout = tarfile.open(tarname, "w:gz") |
8ff5c437 |
tgzout.add(raw_image, arcname=os.path.basename(raw_image))
tgzout.close() |
9b9c0eac |
elif config['artifacttype'] == 'xz': |
039cb7bb |
print("Generating the xz artifact ...") |
9b9c0eac |
utils.runshellcommand("xz -z -k {}".format(raw_image)) |
039cb7bb |
# tarname = img_path + '/photon-' + options.image_name +
# '-' + photon_release_ver + '-' + photon_build_num +
# '.xz' |
9b9c0eac |
# tgzout = tarfile.open(tarname, "w:xz")
# tgzout.add(raw_image, arcname=os.path.basename(raw_image))
# tgzout.close() |
8ff5c437 |
elif config['artifacttype'] == 'vhd': |
94577239 |
relrawpath = os.path.relpath(raw_image, options.src_root) |
039cb7bb |
vhdname = (os.path.dirname(relrawpath) + '/photon-' +
options.image_name + '-' + photon_release_ver + '-' +
photon_build_num + '.vhd')
print("Converting raw disk to vhd ...")
info_output = utils.runshellcommand(
"docker run -v {}:/mnt:rw anishs/qemu-img info -f raw --output json {}"
.format(options.src_root, '/mnt/' + relrawpath)) |
64ead533 |
mbsize = 1024 * 1024 |
b47102eb |
mbroundedsize = ((int(json.loads(info_output)["virtual-size"])/mbsize + 1) * mbsize) |
039cb7bb |
utils.runshellcommand(
"docker run -v {}:/mnt:rw anishs/qemu-img resize -f raw {} {}"
.format(options.src_root, '/mnt/' + relrawpath, mbroundedsize))
utils.runshellcommand(
"docker run -v {}:/mnt:rw anishs/qemu-img convert {} -O "
"vpc -o subformat=fixed,force_size {}"
.format(options.src_root, '/mnt/' + relrawpath, '/mnt/' + vhdname)) |
8ff5c437 |
elif config['artifacttype'] == 'ova': |
039cb7bb |
create_ova_image(raw_image, options.tools_bin_path,
options.build_scripts_path + '/' + options.image_name, config) |
8ff5c437 |
if 'customartifacts' in config:
if 'postinstallscripts' in config['customartifacts']:
custom_path = img_path + '/photon-custom'
if not os.path.exists(custom_path):
os.mkdir(custom_path)
index = 1
for script in config['customartifacts']['postinstallscripts']: |
039cb7bb |
print("Creating custom ova {}...".format(index)) |
8ff5c437 |
if index > 1: |
039cb7bb |
raw_image_custom = (img_path + "/photon-custom-{}".format(index) +
photon_release_ver + '-' +
photon_build_num + '.raw') |
8ff5c437 |
else: |
039cb7bb |
raw_image_custom = (img_path + "/photon-custom-" +
photon_release_ver + '-' +
photon_build_num + '.raw') |
8ff5c437 |
shutil.move(raw_image, raw_image_custom) |
039cb7bb |
disk_device = (
utils.runshellcommand(
"losetup --show -f {}".format(raw_image_custom))).rstrip('\n')
disk_partitions = utils.runshellcommand(
"kpartx -as {}".format(disk_device)) |
8ff5c437 |
device_name = disk_device.split('/')[2] |
039cb7bb |
loop_device_path = "/dev/mapper/{}p2".format(device_name) |
8ff5c437 |
|
039cb7bb |
print("Mounting the loop device for ova customization ...")
utils.runshellcommand(
"mount -t ext4 {} {}".format(loop_device_path, custom_path)) |
8ff5c437 |
if not os.path.exists(custom_path + "/tempscripts"):
os.mkdir(custom_path + "/tempscripts") |
039cb7bb |
shutil.copy(options.build_scripts_path + '/' + options.image_name +
'/' + script, custom_path + "/tempscripts")
print("Running custom ova script {}".format(script))
utils.runshellcommand("chroot {} /bin/bash -c '/tempscripts/{}'"
.format(custom_path, script)) |
8ff5c437 |
shutil.rmtree(custom_path + "/tempscripts", ignore_errors=True)
utils.runshellcommand("umount -l {}".format(custom_path)) |
c061ff83 |
mount_out = utils.runshellcommand("mount") |
039cb7bb |
print("List of mounted devices:")
print(mount_out) |
c061ff83 |
|
8ff5c437 |
utils.runshellcommand("kpartx -d {}".format(disk_device))
utils.runshellcommand("losetup -d {}".format(disk_device)) |
039cb7bb |
create_ova_image(raw_image_custom, options.tools_bin_path,
options.build_scripts_path + '/' + options.image_name,
config) |
8ff5c437 |
raw_image = raw_image_custom
index = index + 1
|
64ead533 |
shutil.rmtree(custom_path) |
8ff5c437 |
else:
raise ValueError("Unknown output format")
if config['keeprawdisk'] == 'false': |
49cc4c52 |
os.remove(raw_image) |