Working virt-install

This commit is contained in:
Neill Cox 2023-09-22 09:30:36 +10:00
parent 494c8b5653
commit eb1fbf7eb4
5 changed files with 145 additions and 17 deletions

View file

@ -1,5 +1,27 @@
A quick and dirty script to help set up a RHOSP AIO 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] usage: main.py [-h] -u USERNAME -p PASSWORD -a ADDRESS [-i INTERFACE]
[-m NETMASK] -d DNS [DNS ...] [-D DOMAIN] [-m NETMASK] -d DNS [DNS ...] [-D DOMAIN]
@ -25,7 +47,7 @@ optional arguments:
--standalone-yaml-out STANDALONE_YAML_OUT --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) By default the files will be placed in the home directory of the user running the script (should probable be the stack user)

6
dev_requirements.txt Normal file
View file

@ -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

View file

@ -4,6 +4,7 @@ import subprocess
MD_PATH = "./meta-data" MD_PATH = "./meta-data"
UD_PATH = "./user-data" UD_PATH = "./user-data"
ND_PATH = "./network-config"
def parse_args(): def parse_args():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
@ -12,7 +13,20 @@ def parse_args():
parser.add_argument("--local-hostname", default="aio3.gpslab.cbr.redhat.com") 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("--user-data", default="./user-data.tpl", type=open)
parser.add_argument("--meta-data", default="./meta-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("--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() args = parser.parse_args()
@ -24,6 +38,19 @@ def parse_args():
args.meta_data = args.meta_data.read() args.meta_data = args.meta_data.read()
args.meta_data = args.meta_data.format(data=args) 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 return args
def write_user_data(user_data): def write_user_data(user_data):
@ -34,35 +61,79 @@ def write_meta_data(meta_data):
with open(MD_PATH, "w", encoding="utf-8") as meta_data_file: with open(MD_PATH, "w", encoding="utf-8") as meta_data_file:
meta_data_file.write(meta_data) 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): def virt_install_cmd(args):
tpl = f""" cmd = f"""
sudo virt-install sudo virt-install \\
--os-variant {args.os_variant} --os-variant {args.os_variant} \\
--name {args.name} --name {args.name} \\
--memory {args.ram} --memory {args.memory} \\
--disk ./test.qcow2 --disk {args.output_image} \\
--import --import \\
--graphics spice,listen=0.0.0.0 --graphics spice,listen=127.0.0.1 \\
--video virtio --video virtio \\
--channel spicevmc --channel spicevmc \\
--wait 0 --wait 0 \\
--cloud-init meta-data=./meta-data,user-data=./user-data --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(): def delete_meta_data():
pathlib.Path.unlink(MD_PATH) pathlib.Path.unlink(pathlib.Path(MD_PATH))
def delete_user_data(): 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(): def main():
args = parse_args() args = parse_args()
print(args) if args.verbose:
print(args)
install_packages(args)
create_image(args)
write_meta_data(args.meta_data) write_meta_data(args.meta_data)
write_user_data(args.user_data) write_user_data(args.user_data)
virt_install_cmd(args)
delete_meta_data() delete_meta_data()
delete_user_data() delete_user_data()

View file

@ -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}

View file

@ -1,6 +1,15 @@
#cloud-config #cloud-config
system_info:
default_user:
name: stack
password: {data.password} password: {data.password}
chpasswd: {{expire: False}} chpasswd: {{expire: False}}
ssh_pwauth: True ssh_pwauth: True
ssh_authorized_keys: ssh_authorized_keys:
- {data.public_key} - {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}"