From 4777fc3db09a36fd977264382ab9c245d66967ff Mon Sep 17 00:00:00 2001 From: Neil Hanlon Date: Sat, 19 Nov 2022 16:27:03 -0500 Subject: [PATCH] begin work on composing vagrant boxes --- iso/empanadas/empanadas/configs/el8.yaml | 3 + iso/empanadas/empanadas/configs/el9.yaml | 3 + .../empanadas/scripts/build_image.py | 85 +++++++++++++------ .../templates/vagrant/Vagrantfile.Libvirt | 0 .../templates/vagrant/Vagrantfile.VMware | 45 ++++++++++ .../templates/vagrant/Vagrantfile.Vbox | 0 .../templates/vagrant/info.tmpl.json | 7 ++ .../templates/vagrant/metadata.tmpl.json | 3 + .../empanadas/templates/vagrant/vmx.tmpl | 59 +++++++++++++ 9 files changed, 181 insertions(+), 24 deletions(-) create mode 100644 iso/empanadas/empanadas/templates/vagrant/Vagrantfile.Libvirt create mode 100644 iso/empanadas/empanadas/templates/vagrant/Vagrantfile.VMware create mode 100644 iso/empanadas/empanadas/templates/vagrant/Vagrantfile.Vbox create mode 100644 iso/empanadas/empanadas/templates/vagrant/info.tmpl.json create mode 100644 iso/empanadas/empanadas/templates/vagrant/metadata.tmpl.json create mode 100644 iso/empanadas/empanadas/templates/vagrant/vmx.tmpl diff --git a/iso/empanadas/empanadas/configs/el8.yaml b/iso/empanadas/empanadas/configs/el8.yaml index 518c5c0..e6427b3 100644 --- a/iso/empanadas/empanadas/configs/el8.yaml +++ b/iso/empanadas/empanadas/configs/el8.yaml @@ -93,6 +93,9 @@ format: raw.xz OCP: format: qcow2 + Vagrant: + format: box + variants: [Libvirt, Vbox, VMware] livemap: git_repo: 'https://git.resf.org/sig_core/kickstarts.git' branch: 'r8' diff --git a/iso/empanadas/empanadas/configs/el9.yaml b/iso/empanadas/empanadas/configs/el9.yaml index 4ddf1e1..e17e5d3 100644 --- a/iso/empanadas/empanadas/configs/el9.yaml +++ b/iso/empanadas/empanadas/configs/el9.yaml @@ -97,6 +97,9 @@ format: raw.xz OCP: format: qcow2 + Vagrant: + format: box + variants: [Libvirt, Vbox, VMware] livemap: git_repo: 'https://git.resf.org/sig_core/kickstarts.git' branch: 'r9' diff --git a/iso/empanadas/empanadas/scripts/build_image.py b/iso/empanadas/empanadas/scripts/build_image.py index f14aa4d..55fa2d0 100644 --- a/iso/empanadas/empanadas/scripts/build_image.py +++ b/iso/empanadas/empanadas/scripts/build_image.py @@ -101,6 +101,25 @@ class ImageBuild: self.checkout_kickstarts() self.kickstart_arg = self.kickstart_imagefactory_args() + try: + os.mkdir(self.outdir) + except FileExistsError as e: + log.info("Directory already exists for this release. If possible, previously executed steps may be skipped") + except Exception as e: + log.exception("Some other exception occured while creating the output directory", e) + return 0 + + if os.path.exists(self.metadata): + with open(self.metadata, "r") as f: + try: + o = json.load(f) + self.base_uuid = o['base_uuid'] + self.target_uuid = o['target_uuid'] + except json.decoder.JSONDecodeError as e: + log.exception("Couldn't decode metadata file", e) + finally: + f.flush() + # Yes, this is gross. I'll fix it later. if self.image_type in ["Container"]: self.stage_commands = [ @@ -127,37 +146,44 @@ class ImageBuild: ] if self.image_type in ["Vagrant"]: _map = { - "Vbox": "vmdk", - "Libvirt": "qcow2", - "VMware": "vmdk" + "Vbox": {"format": "vmdk", "provider": "virtualbox"}, + "Libvirt": {"format": "qcow2", "provider": "libvirt"}, + "VMware": {"format": "vmdk", "convertOptions": ["-o", "subformat=streamOptimized"], "provider": "vmware_desktop"} } - output = f"{_map[self.variant]}" #type: ignore - self.stage_commands = [ - ["qemu-img", "convert", "-c", "-f", "raw", "-O", output, lambda: f"{STORAGE_DIR}/{self.target_uuid}.body", f"{self.outdir}/{self.outname}.{output}"] - ] + output = f"{_map[self.variant]['format']}" #type: ignore + options = f"{_map[self.variant]['convertOptions']}" if 'convertOptions' in _map[self.variant].keys() else '' #type: ignore + provider = f"{_map[self.variant]['provider']}" # type: ignore + self.prepare_vagrant(provider) + self.stage_commands = [ + ["qemu-img", "convert", "-c", "-f", "raw", "-O", output, *options, lambda: f"{STORAGE_DIR}/{self.target_uuid}.body", f"{self.outdir}/{self.outname}.{output}"], + ["tar", "--strip-components=2", "-czf", f"{self.outdir}/{self.outname}.box", f"{self.outdir}"] + ] if self.stage_commands: self.stage_commands.append(["cp", "-v", lambda: f"{STORAGE_DIR}/{self.target_uuid}.meta", f"{self.outdir}/build.meta"]) - try: - os.mkdir(self.outdir) - except FileExistsError as e: - log.info("Directory already exists for this release. If possible, previously executed steps may be skipped") - except Exception as e: - log.exception("Some other exception occured while creating the output directory", e) - return 0 - if os.path.exists(self.metadata): - with open(self.metadata, "r") as f: - try: - o = json.load(f) - self.base_uuid = o['base_uuid'] - self.target_uuid = o['target_uuid'] - except json.decoder.JSONDecodeError as e: - log.exception("Couldn't decode metadata file", e) - finally: - f.flush() + def prepare_vagrant(self, provider): + """Setup the output directory for the Vagrant type variant, dropping templates as required""" + file_loader = FileSystemLoader(f"{_rootdir}/templates") + tmplenv = Environment(loader=file_loader) + + templates = {} + templates['Vagrantfile'] = tmplenv.get_template(f"vagrant/Vagrantfile.{self.variant}") + templates['metadata.json'] = tmplenv.get_template('vagrant/metadata.tmpl.json') + templates['info.json'] = tmplenv.get_template('vagrant/info.tmpl.json') + + if self.variant == "VMware": + provider = "vmware_desktop" + templates[f"{self.outname}.vmx"] = tmplenv.get_template('vagrant/vmx.tmpl') + + for name, template in templates.items(): + print(name, template) + self.render_template(f"{self.outdir}/{name}", template, + name=self.outname, + provider=provider + ) def checkout_kickstarts(self) -> int: cmd = ["git", "clone", "--branch", f"r{self.architecture.major}", rlvars['livemap']['git_repo'], f"{KICKSTART_PATH}"] @@ -225,6 +251,17 @@ class ImageBuild: return ["--file-parameter", "install_script", str(self.kickstart_path)] + def render_template(self, path, template, **kwargs) -> pathlib.Path: + with open(path, "wb") as f: + _template = template.render(**kwargs) + f.write(_template.encode()) + f.flush() + output = pathlib.Path(path) + if not output.exists(): + log.error("Failed to write template") + raise Exception("Failed to template") + return output + def render_icicle_template(self) -> pathlib.Path: handle, output = tempfile.mkstemp() if not handle: diff --git a/iso/empanadas/empanadas/templates/vagrant/Vagrantfile.Libvirt b/iso/empanadas/empanadas/templates/vagrant/Vagrantfile.Libvirt new file mode 100644 index 0000000..e69de29 diff --git a/iso/empanadas/empanadas/templates/vagrant/Vagrantfile.VMware b/iso/empanadas/empanadas/templates/vagrant/Vagrantfile.VMware new file mode 100644 index 0000000..fe3be7e --- /dev/null +++ b/iso/empanadas/empanadas/templates/vagrant/Vagrantfile.VMware @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +# -*- mode: ruby -*- +# vi: set ft=ruby : + +Vagrant.configure("2") do |config| + + # Example configuration of new VM.. + # + #config.vm.define :test_vm do |test_vm| + # Box name + # + #test_vm.vm.box = "rockylinux" + + # Domain Specific Options + # + # See README for more info. + + # Interfaces for VM + # + # Networking features in the form of `config.vm.network` + # + #test_vm.vm.network :private_network, :ip => '10.20.30.40' + #test_vm.vm.network :public_network, :ip => '10.20.30.41' + #end + + # Options for VMware Vagrant provider. + ["vmware_fusion", "vmware_workstation", "vmware_desktop"].each do |provider| + config.vm.provider provider do |vmware, override| + vmware.whitelist_verified = true + vmware.gui = false + + # The machine is configured with 2 cores and 1GB of RAM by default + vmware.vmx["memsize"] = "1024" + vmware.vmx["numvcpus"] = "2" + vmware.vmx["cpuid.coresPerSocket"] = "2" + + # For compatility reasons version 10 (VMware Workstation 10.x and later) + # is used, this can be changed to every later version without any + # other changes if features are needed + # https://kb.vmware.com/s/article/1003746 + vmware.vmx["virtualHW.version"] = "10" + end + end +end diff --git a/iso/empanadas/empanadas/templates/vagrant/Vagrantfile.Vbox b/iso/empanadas/empanadas/templates/vagrant/Vagrantfile.Vbox new file mode 100644 index 0000000..e69de29 diff --git a/iso/empanadas/empanadas/templates/vagrant/info.tmpl.json b/iso/empanadas/empanadas/templates/vagrant/info.tmpl.json new file mode 100644 index 0000000..599b8a3 --- /dev/null +++ b/iso/empanadas/empanadas/templates/vagrant/info.tmpl.json @@ -0,0 +1,7 @@ +{ + "Author": "Rocky Linux Team", + "Website": "https://rockylinux.org/", + "Artifacts": "https://vagrantcloud.com/rockylinux/", + "Repository": "https://git.resf.org/sig_core/toolkit", + "Description": "1st party distributed Vagrant images." +} diff --git a/iso/empanadas/empanadas/templates/vagrant/metadata.tmpl.json b/iso/empanadas/empanadas/templates/vagrant/metadata.tmpl.json new file mode 100644 index 0000000..7674c26 --- /dev/null +++ b/iso/empanadas/empanadas/templates/vagrant/metadata.tmpl.json @@ -0,0 +1,3 @@ +{ + "provider": "{{ provider }}" +} diff --git a/iso/empanadas/empanadas/templates/vagrant/vmx.tmpl b/iso/empanadas/empanadas/templates/vagrant/vmx.tmpl new file mode 100644 index 0000000..1c58ff5 --- /dev/null +++ b/iso/empanadas/empanadas/templates/vagrant/vmx.tmpl @@ -0,0 +1,59 @@ +.encoding = "UTF-8" +bios.bootorder = "hdd,cdrom" +cleanShutdown = "TRUE" +config.version = "8" +cpuid.coresPerSocket = "2" +ehci.present = "FALSE" +firmware = "efi" +floppy0.present = "FALSE" +guestOS = "rhel7_64Guest" +hpet0.present = "TRUE" +mem.hotadd = "TRUE" +memsize = "1024" +numvcpus = "2" +pciBridge0.pciSlotNumber = "17" +pciBridge0.present = "TRUE" +pciBridge4.functions = "8" +pciBridge4.pciSlotNumber = "21" +pciBridge4.present = "TRUE" +pciBridge4.virtualDev = "pcieRootPort" +pciBridge5.functions = "8" +pciBridge5.pciSlotNumber = "22" +pciBridge5.present = "TRUE" +pciBridge5.virtualDev = "pcieRootPort" +pciBridge6.functions = "8" +pciBridge6.pciSlotNumber = "23" +pciBridge6.present = "TRUE" +pciBridge6.virtualDev = "pcieRootPort" +pciBridge7.functions = "8" +pciBridge7.pciSlotNumber = "24" +pciBridge7.present = "TRUE" +pciBridge7.virtualDev = "pcieRootPort" +powerType.powerOff = "soft" +powerType.powerOn = "soft" +powerType.reset = "soft" +powerType.suspend = "soft" +sata0.present = "FALSE" +scsi0:0.present = "TRUE" +scsi0:0.redo = "" +scsi0.pciSlotNumber = "160" +scsi0.present = "TRUE" +scsi0.virtualDev = "pvscsi" +serial0.present = "FALSE" +softPowerOff = "TRUE" +sound.present = "FALSE" +svga.vramSize = "134217728" +tools.syncTime = "TRUE" +usb.present = "FALSE" +uuid.action = "create" +vcpu.hotadd = "TRUE" +virtualHW.productCompatibility = "hosted" +virtualHW.version = "10" +vmci0.id = "-1024033366" +vmci0.present = "TRUE" +vmotion.checkpointFBSize = "134217728" + +displayName = "{{ outname }}" +nvram = "{{ outname }}.nvram" +scsi0:0.fileName = "{{ outname }}.vmdk" +extendedConfigFile = "{{ outname }}.vmxf"