diff --git a/README.md b/README.md index 710f160..f68261e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,27 @@ A quick and dirty script to help set up a RHOSP AIO +This has grown a bit. At some point I will make this a proper readme, but for now a few notes: + +The goal is to build a VM (although you could use baremetal) and deploy a RHOSP AIO to it. Then to add a project, flavors, images, networks to support testing os-migrate. + +After that create a VM to migrate, a conversion host to do the migration. + +This may well be useful for other things, but this is the current aim. + +I am primarily targetting RHEL8.4 and RHOSP16.2. As a result I'm tied to virt-install v3.2.0 which makes using cloud-init for configuring network on the AIO VM a little annoying. Later versions allow you to pass in a network config, but 3.2.0 means I have to use nmcli and bootcmd to get the network configure. + +There is a vestigial network-config.tpl in the virt-install directory but it is not actually used yet. + +EVerything is a bit of a mess but here's a brief overview: + +main.py - original script. Generates the yaml files and a dploy script to deploy a RHOSP AIO. Assumes a VM to run on. Don't run this on your laptop. You'll be sorry if you do. + +os_migrate_setup.py - build the OSP infrastructure to allow testing os-migrate. + +os_migrate_teardown.py - remove that infrastructure (to allow for refinement/iteration) + +virt-install/create_aio_vm.py - use virt-install to create and configure a VM to run the other scripts on. + ``` usage: main.py [-h] -u USERNAME -p PASSWORD -a ADDRESS [-i INTERFACE] [-m NETMASK] -d DNS [DNS ...] [-D DOMAIN] @@ -25,7 +47,7 @@ optional arguments: --standalone-yaml-out STANDALONE_YAML_OUT ``` -Use this script to generate the yaml and a deploy script to buyild an AIO +Use this script to generate the yaml and a deploy script to build an AIO By default the files will be placed in the home directory of the user running the script (should probable be the stack user) diff --git a/dev_requirements.txt b/dev_requirements.txt new file mode 100644 index 0000000..d2c4c65 --- /dev/null +++ b/dev_requirements.txt @@ -0,0 +1,6 @@ +black==22.8.0 +bpython==0.22.1 +flake8==5.0.4 +pyflakes==2.5.0 +pylint==2.13.9 +PyYAML==6.0.1 diff --git a/virt-install/create_aio_vm.py b/virt-install/create_aio_vm.py index 02aae88..756fe34 100644 --- a/virt-install/create_aio_vm.py +++ b/virt-install/create_aio_vm.py @@ -4,6 +4,7 @@ import subprocess MD_PATH = "./meta-data" UD_PATH = "./user-data" +ND_PATH = "./network-config" def parse_args(): parser = argparse.ArgumentParser() @@ -12,7 +13,20 @@ def parse_args(): parser.add_argument("--local-hostname", default="aio3.gpslab.cbr.redhat.com") parser.add_argument("--user-data", default="./user-data.tpl", type=open) parser.add_argument("--meta-data", default="./meta-data.tpl", type=open) + parser.add_argument("--network-data", default="./network-config.tpl", type=open) parser.add_argument("--instance-id", default="aio3") + parser.add_argument("--output-image", required=True) + parser.add_argument("--image-size", default="100G") + parser.add_argument("--input-image", required=True) + parser.add_argument("--os-variant", required=True) + parser.add_argument("--name", required=True) + parser.add_argument("--memory", default=2048) #, type="int") + parser.add_argument("--gateway", required=True) + parser.add_argument("--cidr-1", required=True) + parser.add_argument("--cidr-2", required=True) + parser.add_argument("--dns", required=True) + parser.add_argument("--search-domain", required=True) + parser.add_argument("-v", "--verbose", action="store_true") args = parser.parse_args() @@ -23,6 +37,19 @@ def parse_args(): args.meta_data = args.meta_data.read() args.meta_data = args.meta_data.format(data=args) + + args.network_data = args.network_data.read() + args.network_data = args.network_data.format(data=args) + + output_image = pathlib.Path(args.output_image) + if output_image.exists(): + raise ValueError(f"{args.output_image} already exists") + args.output_image = output_image + + input_image = pathlib.Path(args.input_image) + if not input_image.exists(): + raise ValueError(f"{args.input_image} not found") + args.input_image = input_image return args @@ -34,35 +61,79 @@ def write_meta_data(meta_data): with open(MD_PATH, "w", encoding="utf-8") as meta_data_file: meta_data_file.write(meta_data) +def write_network_data(network_data): + with open(ND_PATH, "w", encoding="utf-8") as network_data_file: + network_data_file.write(network_data) + +def create_image(args): + print("creating image") + cmd = f"qemu-img create -f qcow2 -o preallocation=metadata {args.output_image} {args.image_size}" + + result = subprocess.check_output(cmd, shell=True, universal_newlines=True) + if args.verbose: + print(result) + + print("Resizing image") + cmd = f"virt-resize --expand /dev/sda3 {args.input_image} {args.output_image}" + + result= subprocess.check_output(cmd, shell=True, universal_newlines=True) + + if args.verbose: + print(result) + def virt_install_cmd(args): - tpl = f""" - sudo virt-install - --os-variant {args.os_variant} - --name {args.name} - --memory {args.ram} - --disk ./test.qcow2 - --import - --graphics spice,listen=0.0.0.0 - --video virtio - --channel spicevmc - --wait 0 - --cloud-init meta-data=./meta-data,user-data=./user-data + cmd = f""" + sudo virt-install \\ + --os-variant {args.os_variant} \\ + --name {args.name} \\ + --memory {args.memory} \\ + --disk {args.output_image} \\ + --import \\ + --graphics spice,listen=127.0.0.1 \\ + --video virtio \\ + --channel spicevmc \\ + --wait 0 \\ + --cloud-init meta-data=./meta-data,user-data=./user-data \\ + --network bridge=bridge0 \\ + --network bridge=bridge0 """ + + print("running virt-install") + + if args.verbose: + print(cmd) + + result =subprocess.check_output(cmd, shell=True, universal_newlines=True) + if args.verbose: + print(result) + def delete_meta_data(): - pathlib.Path.unlink(MD_PATH) + pathlib.Path.unlink(pathlib.Path(MD_PATH)) def delete_user_data(): - pathlib.Path.unlink(UD_PATH) + pathlib.Path.unlink(pathlib.Path(UD_PATH)) + +def install_packages(args): + cmd = "sudo dnf install -y virt-install virt-viewer qemu-img libguestfs.x86_64" + + print("installing needed packages...") + + if args.verbose: + print(subprocess.check_output(cmd, shell=True, universal_newlines=True)) def main(): args = parse_args() - print(args) + if args.verbose: + print(args) + + install_packages(args) + create_image(args) write_meta_data(args.meta_data) write_user_data(args.user_data) - + virt_install_cmd(args) delete_meta_data() delete_user_data() diff --git a/virt-install/network-config.tpl b/virt-install/network-config.tpl new file mode 100644 index 0000000..019c43f --- /dev/null +++ b/virt-install/network-config.tpl @@ -0,0 +1,20 @@ +network: + version: 1 + config: + - type: physical + name: en0 + subnets: + - type: static + address: {data.cidr_1} + gateway: {data.gateway} + - type: physical + name: en1 + subnets: + - type: static + address: {data.cidr_2} + gateway: {data.gateway} + - type: nameserver + address: + - {data.dns} + search: + - {data.search_domain} \ No newline at end of file diff --git a/virt-install/user-data.tpl b/virt-install/user-data.tpl index ea2c172..5a338b4 100644 --- a/virt-install/user-data.tpl +++ b/virt-install/user-data.tpl @@ -1,6 +1,15 @@ #cloud-config +system_info: + default_user: + name: stack password: {data.password} chpasswd: {{expire: False}} ssh_pwauth: True ssh_authorized_keys: - {data.public_key} + +bootcmd: + - "nmcli conn delete 'System eth0'" + - "nmcli conn delete 'Wired connection 1'" + - "nmcli con add con-name eth0 ifname eth0 type ethernet ip4 {data.cidr_1} gw4 {data.gateway} ipv4.dns {data.dns}" + - "nmcli con add con-name eth1 ifname eth1 type ethernet ip4 {data.cidr_2} gw4 {data.gateway} ipv4.dns {data.dns}"