Compare commits
8 Commits
6e2c1fb45e
...
191f8780c9
Author | SHA1 | Date | |
---|---|---|---|
191f8780c9 | |||
80c1f78864 | |||
c8c0987fe7 | |||
67560c6457 | |||
79c9eba28c | |||
36e924d339 | |||
aeb1443410 | |||
eccd2a98b2 |
@ -116,7 +116,7 @@
|
|||||||
# }
|
# }
|
||||||
|
|
||||||
|
|
||||||
from pvcapi.vmbuilder import VMBuilder
|
from pvcapi.vmbuilder import VMBuilder, ProvisioningError
|
||||||
|
|
||||||
|
|
||||||
class VMBuilderScript(VMBuilder):
|
class VMBuilderScript(VMBuilder):
|
||||||
@ -211,7 +211,7 @@ class VMBuilderScript(VMBuilder):
|
|||||||
|
|
||||||
schema += libvirt_schema.devices_net_interface.format(
|
schema += libvirt_schema.devices_net_interface.format(
|
||||||
eth_macaddr=eth_macaddr,
|
eth_macaddr=eth_macaddr,
|
||||||
eth_bridge=eth_bridge,
|
eth_bridge=network["eth_bridge"],
|
||||||
)
|
)
|
||||||
|
|
||||||
network_id += 1
|
network_id += 1
|
||||||
@ -255,6 +255,13 @@ class VMBuilderScript(VMBuilder):
|
|||||||
block devices and map them to the host.
|
block devices and map them to the host.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# Run any imports first
|
||||||
|
import os
|
||||||
|
from pvcapid.vmbuilder import open_zk
|
||||||
|
from pvcapid.Daemon import config
|
||||||
|
import daemon_lib.common as pvc_common
|
||||||
|
import daemon_lib.ceph as pvc_ceph
|
||||||
|
|
||||||
# First loop: Create the disks, either by cloning (pvc_ceph.clone_volume), or by
|
# First loop: Create the disks, either by cloning (pvc_ceph.clone_volume), or by
|
||||||
# new creation (pvc_ceph.add_volume).
|
# new creation (pvc_ceph.add_volume).
|
||||||
for volume in self.vm_data["volumes"]:
|
for volume in self.vm_data["volumes"]:
|
||||||
@ -297,7 +304,7 @@ class VMBuilderScript(VMBuilder):
|
|||||||
dst_volume_name,
|
dst_volume_name,
|
||||||
)
|
)
|
||||||
print(message)
|
print(message)
|
||||||
if not retcode:
|
if not success:
|
||||||
raise ProvisioningError(f"Failed to map volume '{dst_volume}'.")
|
raise ProvisioningError(f"Failed to map volume '{dst_volume}'.")
|
||||||
|
|
||||||
# Third loop: Create filesystems on the volumes
|
# Third loop: Create filesystems on the volumes
|
||||||
@ -340,7 +347,7 @@ class VMBuilderScript(VMBuilder):
|
|||||||
|
|
||||||
# Create a temporary directory to use during install
|
# Create a temporary directory to use during install
|
||||||
temp_dir = "/tmp/target"
|
temp_dir = "/tmp/target"
|
||||||
if not os.exists(temp_dir):
|
if not os.path.isdir(temp_dir):
|
||||||
os.mkdir(temp_dir)
|
os.mkdir(temp_dir)
|
||||||
|
|
||||||
# Fourth loop: Mount the volumes to a set of temporary directories
|
# Fourth loop: Mount the volumes to a set of temporary directories
|
||||||
@ -358,7 +365,7 @@ class VMBuilderScript(VMBuilder):
|
|||||||
|
|
||||||
mount_path = f"{temp_dir}/{volume['mountpoint']}"
|
mount_path = f"{temp_dir}/{volume['mountpoint']}"
|
||||||
|
|
||||||
if not os.exists(mount_path):
|
if not os.path.isdir(mount_path):
|
||||||
os.mkdir(mount_path)
|
os.mkdir(mount_path)
|
||||||
|
|
||||||
# Mount filesystem
|
# Mount filesystem
|
||||||
@ -394,6 +401,12 @@ class VMBuilderScript(VMBuilder):
|
|||||||
need cleanup before teardown of the overlay chroot environment.
|
need cleanup before teardown of the overlay chroot environment.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# Run any imports first
|
||||||
|
from pvcapid.vmbuilder import open_zk
|
||||||
|
from pvcapid.Daemon import config
|
||||||
|
import daemon_lib.common as pvc_common
|
||||||
|
import daemon_lib.ceph as pvc_ceph
|
||||||
|
|
||||||
temp_dir = "/tmp/target"
|
temp_dir = "/tmp/target"
|
||||||
|
|
||||||
for volume in list(reversed(self.vm_data["volumes"])):
|
for volume in list(reversed(self.vm_data["volumes"])):
|
||||||
|
@ -116,7 +116,7 @@
|
|||||||
# }
|
# }
|
||||||
|
|
||||||
|
|
||||||
from pvcapid.vmbuilder import VMBuilder
|
from pvcapid.vmbuilder import VMBuilder, ProvisioningError
|
||||||
|
|
||||||
|
|
||||||
class VMBuilderScript(VMBuilder):
|
class VMBuilderScript(VMBuilder):
|
||||||
@ -215,7 +215,7 @@ class VMBuilderScript(VMBuilder):
|
|||||||
|
|
||||||
schema += libvirt_schema.devices_net_interface.format(
|
schema += libvirt_schema.devices_net_interface.format(
|
||||||
eth_macaddr=eth_macaddr,
|
eth_macaddr=eth_macaddr,
|
||||||
eth_bridge=eth_bridge,
|
eth_bridge=network["eth_bridge"],
|
||||||
)
|
)
|
||||||
|
|
||||||
network_id += 1
|
network_id += 1
|
||||||
@ -259,6 +259,13 @@ class VMBuilderScript(VMBuilder):
|
|||||||
block devices and map them to the host.
|
block devices and map them to the host.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# Run any imports first
|
||||||
|
import os
|
||||||
|
from pvcapid.vmbuilder import open_zk
|
||||||
|
from pvcapid.Daemon import config
|
||||||
|
import daemon_lib.common as pvc_common
|
||||||
|
import daemon_lib.ceph as pvc_ceph
|
||||||
|
|
||||||
# First loop: Create the disks, either by cloning (pvc_ceph.clone_volume), or by
|
# First loop: Create the disks, either by cloning (pvc_ceph.clone_volume), or by
|
||||||
# new creation (pvc_ceph.add_volume).
|
# new creation (pvc_ceph.add_volume).
|
||||||
for volume in self.vm_data["volumes"]:
|
for volume in self.vm_data["volumes"]:
|
||||||
@ -301,7 +308,7 @@ class VMBuilderScript(VMBuilder):
|
|||||||
dst_volume_name,
|
dst_volume_name,
|
||||||
)
|
)
|
||||||
print(message)
|
print(message)
|
||||||
if not retcode:
|
if not success:
|
||||||
raise ProvisioningError(f"Failed to map volume '{dst_volume}'.")
|
raise ProvisioningError(f"Failed to map volume '{dst_volume}'.")
|
||||||
|
|
||||||
# Third loop: Create filesystems on the volumes
|
# Third loop: Create filesystems on the volumes
|
||||||
@ -344,7 +351,8 @@ class VMBuilderScript(VMBuilder):
|
|||||||
|
|
||||||
# Create a temporary directory to use during install
|
# Create a temporary directory to use during install
|
||||||
temp_dir = "/tmp/target"
|
temp_dir = "/tmp/target"
|
||||||
if not os.exists(temp_dir):
|
|
||||||
|
if not os.path.isdir(temp_dir):
|
||||||
os.mkdir(temp_dir)
|
os.mkdir(temp_dir)
|
||||||
|
|
||||||
# Fourth loop: Mount the volumes to a set of temporary directories
|
# Fourth loop: Mount the volumes to a set of temporary directories
|
||||||
@ -362,7 +370,7 @@ class VMBuilderScript(VMBuilder):
|
|||||||
|
|
||||||
mount_path = f"{temp_dir}/{volume['mountpoint']}"
|
mount_path = f"{temp_dir}/{volume['mountpoint']}"
|
||||||
|
|
||||||
if not os.exists(mount_path):
|
if not os.path.isdir(mount_path):
|
||||||
os.mkdir(mount_path)
|
os.mkdir(mount_path)
|
||||||
|
|
||||||
# Mount filesystem
|
# Mount filesystem
|
||||||
@ -383,6 +391,7 @@ class VMBuilderScript(VMBuilder):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# Run any imports first
|
# Run any imports first
|
||||||
|
import os
|
||||||
from pvcapid.vmbuilder import chroot
|
from pvcapid.vmbuilder import chroot
|
||||||
|
|
||||||
# The directory we mounted things on earlier during prepare()
|
# The directory we mounted things on earlier during prepare()
|
||||||
@ -390,7 +399,7 @@ class VMBuilderScript(VMBuilder):
|
|||||||
|
|
||||||
# Use these convenient aliases for later (avoiding lots of "self.vm_data" everywhere)
|
# Use these convenient aliases for later (avoiding lots of "self.vm_data" everywhere)
|
||||||
vm_name = self.vm_name
|
vm_name = self.vm_name
|
||||||
disks = self.vm_data["disks"]
|
volumes = self.vm_data["volumes"]
|
||||||
networks = self.vm_data["networks"]
|
networks = self.vm_data["networks"]
|
||||||
|
|
||||||
# Parse these arguments out of self.vm_data["script_arguments"]
|
# Parse these arguments out of self.vm_data["script_arguments"]
|
||||||
@ -419,11 +428,11 @@ class VMBuilderScript(VMBuilder):
|
|||||||
|
|
||||||
# We need to know our root disk
|
# We need to know our root disk
|
||||||
root_disk = None
|
root_disk = None
|
||||||
for disk in disks:
|
for volume in volumes:
|
||||||
if disk["mountpoint"] == "/":
|
if volume["mountpoint"] == "/":
|
||||||
root_disk = disk
|
root_volume = volume
|
||||||
if not root_disk:
|
if not root_volume:
|
||||||
raise ProvisioningError("Failed to find root disk in disks list")
|
raise ProvisioningError("Failed to find root volume in volumes list")
|
||||||
|
|
||||||
# Perform a deboostrap installation
|
# Perform a deboostrap installation
|
||||||
os.system(
|
os.system(
|
||||||
@ -438,25 +447,25 @@ class VMBuilderScript(VMBuilder):
|
|||||||
# Bind mount the devfs
|
# Bind mount the devfs
|
||||||
os.system("mount --bind /dev {}/dev".format(temporary_directory))
|
os.system("mount --bind /dev {}/dev".format(temporary_directory))
|
||||||
|
|
||||||
# Create an fstab entry for each disk
|
# Create an fstab entry for each volume
|
||||||
fstab_file = "{}/etc/fstab".format(temporary_directory)
|
fstab_file = "{}/etc/fstab".format(temporary_directory)
|
||||||
# The disk ID starts at zero and increments by one for each disk in the fixed-order
|
# The volume ID starts at zero and increments by one for each volume in the fixed-order
|
||||||
# disk list. This lets us work around the insanity of Libvirt IDs not matching guest IDs,
|
# volume list. This lets us work around the insanity of Libvirt IDs not matching guest IDs,
|
||||||
# while still letting us have some semblance of control here without enforcing things
|
# while still letting us have some semblance of control here without enforcing things
|
||||||
# like labels. It increments in the for loop below at the end of each iteration, and is
|
# like labels. It increments in the for loop below at the end of each iteration, and is
|
||||||
# used to craft a /dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi0-0-0-X device ID
|
# used to craft a /dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi0-0-0-X device ID
|
||||||
# which will always match the correct order from Libvirt (unlike sdX/vdX names).
|
# which will always match the correct order from Libvirt (unlike sdX/vdX names).
|
||||||
disk_id = 0
|
volume_id = 0
|
||||||
for disk in disks:
|
for volume in volumes:
|
||||||
# We assume SSD-based/-like storage, and dislike atimes
|
# We assume SSD-based/-like storage, and dislike atimes
|
||||||
options = "defaults,discard,noatime,nodiratime"
|
options = "defaults,discard,noatime,nodiratime"
|
||||||
|
|
||||||
# The root, var, and log volumes have specific values
|
# The root, var, and log volumes have specific values
|
||||||
if disk["mountpoint"] == "/":
|
if volume["mountpoint"] == "/":
|
||||||
root_disk["scsi_id"] = disk_id
|
root_volume["scsi_id"] = volume_id
|
||||||
dump = 0
|
dump = 0
|
||||||
cpass = 1
|
cpass = 1
|
||||||
elif disk["mountpoint"] == "/var" or disk["mountpoint"] == "/var/log":
|
elif volume["mountpoint"] == "/var" or volume["mountpoint"] == "/var/log":
|
||||||
dump = 0
|
dump = 0
|
||||||
cpass = 2
|
cpass = 2
|
||||||
else:
|
else:
|
||||||
@ -465,18 +474,18 @@ class VMBuilderScript(VMBuilder):
|
|||||||
|
|
||||||
# Append the fstab line
|
# Append the fstab line
|
||||||
with open(fstab_file, "a") as fh:
|
with open(fstab_file, "a") as fh:
|
||||||
data = "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi0-0-0-{disk} {mountpoint} {filesystem} {options} {dump} {cpass}\n".format(
|
data = "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi0-0-0-{volume} {mountpoint} {filesystem} {options} {dump} {cpass}\n".format(
|
||||||
disk=disk_id,
|
volume=volume_id,
|
||||||
mountpoint=disk["mountpoint"],
|
mountpoint=volume["mountpoint"],
|
||||||
filesystem=disk["filesystem"],
|
filesystem=volume["filesystem"],
|
||||||
options=options,
|
options=options,
|
||||||
dump=dump,
|
dump=dump,
|
||||||
cpass=cpass,
|
cpass=cpass,
|
||||||
)
|
)
|
||||||
fh.write(data)
|
fh.write(data)
|
||||||
|
|
||||||
# Increment the disk_id
|
# Increment the volume_id
|
||||||
disk_id += 1
|
volume_id += 1
|
||||||
|
|
||||||
# Write the hostname
|
# Write the hostname
|
||||||
hostname_file = "{}/etc/hostname".format(temporary_directory)
|
hostname_file = "{}/etc/hostname".format(temporary_directory)
|
||||||
@ -539,13 +548,13 @@ interface "ens2" {
|
|||||||
GRUB_DEFAULT=0
|
GRUB_DEFAULT=0
|
||||||
GRUB_TIMEOUT=1
|
GRUB_TIMEOUT=1
|
||||||
GRUB_DISTRIBUTOR="PVC Virtual Machine"
|
GRUB_DISTRIBUTOR="PVC Virtual Machine"
|
||||||
GRUB_CMDLINE_LINUX_DEFAULT="root=/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi0-0-0-{root_disk} console=tty0 console=ttyS0,115200n8"
|
GRUB_CMDLINE_LINUX_DEFAULT="root=/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi0-0-0-{root_volume} console=tty0 console=ttyS0,115200n8"
|
||||||
GRUB_CMDLINE_LINUX=""
|
GRUB_CMDLINE_LINUX=""
|
||||||
GRUB_TERMINAL=console
|
GRUB_TERMINAL=console
|
||||||
GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1"
|
GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1"
|
||||||
GRUB_DISABLE_LINUX_UUID=false
|
GRUB_DISABLE_LINUX_UUID=false
|
||||||
""".format(
|
""".format(
|
||||||
root_disk=root_disk["scsi_id"]
|
root_volume=root_volume["scsi_id"]
|
||||||
)
|
)
|
||||||
fh.write(data)
|
fh.write(data)
|
||||||
|
|
||||||
@ -554,7 +563,7 @@ GRUB_DISABLE_LINUX_UUID=false
|
|||||||
# Install and update GRUB
|
# Install and update GRUB
|
||||||
os.system(
|
os.system(
|
||||||
"grub-install --force /dev/rbd/{}/{}_{}".format(
|
"grub-install --force /dev/rbd/{}/{}_{}".format(
|
||||||
root_disk["pool"], vm_name, root_disk["disk_id"]
|
root_volume["pool"], vm_name, root_volume["disk_id"]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
os.system("update-grub")
|
os.system("update-grub")
|
||||||
@ -577,6 +586,12 @@ GRUB_DISABLE_LINUX_UUID=false
|
|||||||
need cleanup before teardown of the overlay chroot environment.
|
need cleanup before teardown of the overlay chroot environment.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# Run any imports first
|
||||||
|
from pvcapid.vmbuilder import open_zk
|
||||||
|
from pvcapid.Daemon import config
|
||||||
|
import daemon_lib.common as pvc_common
|
||||||
|
import daemon_lib.ceph as pvc_ceph
|
||||||
|
|
||||||
temp_dir = "/tmp/target"
|
temp_dir = "/tmp/target"
|
||||||
|
|
||||||
for volume in list(reversed(self.vm_data["volumes"])):
|
for volume in list(reversed(self.vm_data["volumes"])):
|
||||||
|
@ -159,9 +159,13 @@ def open_db(config):
|
|||||||
password=config["database_password"],
|
password=config["database_password"],
|
||||||
)
|
)
|
||||||
cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
|
cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
|
||||||
yield cur
|
|
||||||
except Exception:
|
except Exception:
|
||||||
raise ClusterError("Failed to connect to Postgres")
|
raise ClusterError("Failed to connect to Postgres")
|
||||||
|
|
||||||
|
try:
|
||||||
|
yield cur
|
||||||
|
except Exception:
|
||||||
|
raise
|
||||||
finally:
|
finally:
|
||||||
conn.commit()
|
conn.commit()
|
||||||
cur.close()
|
cur.close()
|
||||||
@ -174,9 +178,13 @@ def open_zk(config):
|
|||||||
try:
|
try:
|
||||||
zkhandler = ZKHandler(config)
|
zkhandler = ZKHandler(config)
|
||||||
zkhandler.connect()
|
zkhandler.connect()
|
||||||
yield zkhandler
|
|
||||||
except Exception:
|
except Exception:
|
||||||
raise ClusterError("Failed to connect to Zookeeper")
|
raise ClusterError("Failed to connect to Zookeeper")
|
||||||
|
|
||||||
|
try:
|
||||||
|
yield zkhandler
|
||||||
|
except Exception:
|
||||||
|
raise
|
||||||
finally:
|
finally:
|
||||||
zkhandler.disconnect()
|
zkhandler.disconnect()
|
||||||
del zkhandler
|
del zkhandler
|
||||||
@ -613,7 +621,7 @@ def create_vm(
|
|||||||
vm_builder.setup()
|
vm_builder.setup()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
general_cleanup()
|
general_cleanup()
|
||||||
raise ProvisioningError(f"Error in setup(): {e}")
|
raise ProvisioningError(f"Error in script setup() step: {e}")
|
||||||
|
|
||||||
# Phase 5 - script: create()
|
# Phase 5 - script: create()
|
||||||
# * Prepare the libvirt XML defintion for the VM
|
# * Prepare the libvirt XML defintion for the VM
|
||||||
@ -635,7 +643,7 @@ def create_vm(
|
|||||||
vm_schema = vm_builder.create()
|
vm_schema = vm_builder.create()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
general_cleanup()
|
general_cleanup()
|
||||||
raise ProvisioningError(f"Error in create(): {e}")
|
raise ProvisioningError(f"Error in script create() step: {e}")
|
||||||
|
|
||||||
print("Generated VM schema:\n{}\n".format(vm_schema))
|
print("Generated VM schema:\n{}\n".format(vm_schema))
|
||||||
|
|
||||||
@ -680,8 +688,10 @@ def create_vm(
|
|||||||
with chroot(temp_dir):
|
with chroot(temp_dir):
|
||||||
vm_builder.prepare()
|
vm_builder.prepare()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
with chroot(temp_dir):
|
||||||
|
vm_builder.cleanup()
|
||||||
general_cleanup()
|
general_cleanup()
|
||||||
raise ProvisioningError(f"Error in prepare(): {e}")
|
raise ProvisioningError(f"Error in script prepare() step: {e}")
|
||||||
|
|
||||||
# Phase 7 - script: install()
|
# Phase 7 - script: install()
|
||||||
# * Run installation with arguments
|
# * Run installation with arguments
|
||||||
@ -701,8 +711,10 @@ def create_vm(
|
|||||||
with chroot(temp_dir):
|
with chroot(temp_dir):
|
||||||
vm_builder.install()
|
vm_builder.install()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
with chroot(temp_dir):
|
||||||
|
vm_builder.cleanup()
|
||||||
general_cleanup()
|
general_cleanup()
|
||||||
raise ProvisioningError(f"Error in install(): {e}")
|
raise ProvisioningError(f"Error in script install() step: {e}")
|
||||||
|
|
||||||
# Phase 8 - script: cleanup()
|
# Phase 8 - script: cleanup()
|
||||||
# * Run cleanup steps
|
# * Run cleanup steps
|
||||||
@ -723,7 +735,7 @@ def create_vm(
|
|||||||
vm_builder.cleanup()
|
vm_builder.cleanup()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
general_cleanup()
|
general_cleanup()
|
||||||
raise ProvisioningError(f"Error in cleanup(): {e}")
|
raise ProvisioningError(f"Error in script cleanup() step: {e}")
|
||||||
|
|
||||||
# Phase 9 - general cleanup
|
# Phase 9 - general cleanup
|
||||||
# * Clean up the chroot from earlier
|
# * Clean up the chroot from earlier
|
||||||
@ -756,3 +768,9 @@ def create_vm(
|
|||||||
with open_zk(config) as zkhandler:
|
with open_zk(config) as zkhandler:
|
||||||
success, message = pvc_vm.start_vm(zkhandler, vm_name)
|
success, message = pvc_vm.start_vm(zkhandler, vm_name)
|
||||||
print(message)
|
print(message)
|
||||||
|
|
||||||
|
end_message = f'VM "{vm_name}" with profile "{vm_profile}" has been provisioned and started successfully'
|
||||||
|
else:
|
||||||
|
end_message = f'VM "{vm_name}" with profile "{vm_profile}" has been provisioned successfully'
|
||||||
|
|
||||||
|
return {"status": end_message, "current": 10, "total": 10}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user