Initial implementation (no networking) of uncloud-oneshot
This commit is contained in:
parent
e2cd44826b
commit
618fecb73f
4 changed files with 139 additions and 0 deletions
|
@ -16,6 +16,7 @@ ETCD_COMPONENTS = ['api', 'scheduler', 'host', 'filescanner',
|
||||||
'imagescanner', 'metadata', 'configure', 'hack']
|
'imagescanner', 'metadata', 'configure', 'hack']
|
||||||
|
|
||||||
ALL_COMPONENTS = ETCD_COMPONENTS.copy()
|
ALL_COMPONENTS = ETCD_COMPONENTS.copy()
|
||||||
|
ALL_COMPONENTS.append('oneshot')
|
||||||
#ALL_COMPONENTS.append('cli')
|
#ALL_COMPONENTS.append('cli')
|
||||||
|
|
||||||
|
|
||||||
|
|
3
uncloud/oneshot/__init__.py
Normal file
3
uncloud/oneshot/__init__.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
65
uncloud/oneshot/main.py
Normal file
65
uncloud/oneshot/main.py
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
from uncloud.vmm import VMM
|
||||||
|
|
||||||
|
from . import virtualmachine, logger
|
||||||
|
|
||||||
|
arg_parser = argparse.ArgumentParser('oneshot', add_help=False)
|
||||||
|
arg_parser.add_argument('--workdir', default=Path.home())
|
||||||
|
arg_parser.add_argument('--list-vms', action='store_true')
|
||||||
|
arg_parser.add_argument('--start-vm', action='store_true')
|
||||||
|
arg_parser.add_argument('--stop-vm', action='store_true')
|
||||||
|
arg_parser.add_argument('--name')
|
||||||
|
arg_parser.add_argument('--image')
|
||||||
|
arg_parser.add_argument('--uuid')
|
||||||
|
arg_parser.add_argument('--mac')
|
||||||
|
arg_parser.add_argument('--get_vm_status', action='store_true')
|
||||||
|
arg_parser.add_argument('--setup-network')
|
||||||
|
|
||||||
|
def setup_network():
|
||||||
|
print("Not implemented yet.")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
def require_with(arguments, required, mode):
|
||||||
|
if not arguments[required]:
|
||||||
|
print("--{} is required with the {} flag. Exiting.".format(required, mode))
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
def main(arguments):
|
||||||
|
# Initialize VMM
|
||||||
|
workdir = arguments['workdir']
|
||||||
|
vmm = VMM(vmm_backend=workdir)
|
||||||
|
|
||||||
|
# Initialize workdir directory.
|
||||||
|
# TODO: copy ifup, ifdown.
|
||||||
|
|
||||||
|
# Build VM configuration.
|
||||||
|
vm_config = {}
|
||||||
|
for spec in ['uuid', 'memory', 'cores', 'threads', 'image', 'image_format', 'name']:
|
||||||
|
if arguments.get(spec):
|
||||||
|
vm_config[spec] = arguments[spec]
|
||||||
|
|
||||||
|
# Execute requested VM action.
|
||||||
|
vm = virtualmachine.VM(vmm, vm_config)
|
||||||
|
if arguments['setup_network']:
|
||||||
|
setup_network()
|
||||||
|
elif arguments['start_vm']:
|
||||||
|
require_with(arguments, 'image', 'start_vm')
|
||||||
|
vm.start()
|
||||||
|
logger.info("Created VM {}".format(vm.get_uuid))
|
||||||
|
elif arguments['get_vm_status']:
|
||||||
|
require_with(arguments, 'uuid', 'get_vm_status')
|
||||||
|
print("VM: {} {} {}".format(vm.get_uuid(), vm.get_name(), vm.get_status()))
|
||||||
|
elif arguments['stop_vm']:
|
||||||
|
require_with(arguments, 'uuid', 'stop_vm')
|
||||||
|
vm.stop()
|
||||||
|
elif arguments['list_vms']:
|
||||||
|
discovered = vmm.discover()
|
||||||
|
print("Found {} VMs.".format(len(discovered)))
|
||||||
|
for uuid in vmm.discover():
|
||||||
|
vmi = virtualmachine.VM(vmm, {'uuid': uuid})
|
||||||
|
print("VM: {} {} {}".format(vmi.get_uuid, vmi.get_name, vmi.get_status))
|
||||||
|
else:
|
||||||
|
print('No action requested. Exiting.')
|
70
uncloud/oneshot/virtualmachine.py
Normal file
70
uncloud/oneshot/virtualmachine.py
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import uuid
|
||||||
|
import os
|
||||||
|
|
||||||
|
from uncloud.oneshot import logger
|
||||||
|
|
||||||
|
class VM(object):
|
||||||
|
def __init__(self, vmm, config):
|
||||||
|
self.config = config
|
||||||
|
self.vmm = vmm
|
||||||
|
|
||||||
|
# Extract VM specs/metadata from configuration.
|
||||||
|
self.name = config.get('name')
|
||||||
|
self.memory = config.get('memory', 1024)
|
||||||
|
self.cores = config.get('cores', 1)
|
||||||
|
self.threads = config.get('threads', 1)
|
||||||
|
self.image_format = config.get('image_format', 'qcow2')
|
||||||
|
self.image = config.get('image')
|
||||||
|
self.uuid = config.get('uuid', uuid.uuid4())
|
||||||
|
self.mac = config.get('mac', 'spuik')
|
||||||
|
|
||||||
|
# Harcoded & generated values.
|
||||||
|
self.image_format='qcow2'
|
||||||
|
self.accel = 'kvm'
|
||||||
|
|
||||||
|
def get_qemu_args(self):
|
||||||
|
command = (
|
||||||
|
"-uuid {uuid} -name {name}"
|
||||||
|
" -drive file={image},format={image_format},if=virtio"
|
||||||
|
" -device virtio-rng-pci"
|
||||||
|
" -m {memory} -smp cores={cores},threads={threads}"
|
||||||
|
).format(
|
||||||
|
uuid=self.uuid, name=self.name,
|
||||||
|
image=self.image, image_format=self.image_format,
|
||||||
|
memory=self.memory, cores=self.cores, threads=self.threads,
|
||||||
|
)
|
||||||
|
|
||||||
|
return command.split(" ")
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
# Check that VM image is available.
|
||||||
|
if not os.path.isfile(self.image):
|
||||||
|
logger.error("Image {} does not exist. Aborting.".format(self.image))
|
||||||
|
|
||||||
|
# Generate config for and run QEMU.
|
||||||
|
qemu_args = self.get_qemu_args()
|
||||||
|
logger.warning("QEMU args for VM {}: {}".format(self.uuid, qemu_args))
|
||||||
|
self.vmm.start(
|
||||||
|
uuid=self.uuid,
|
||||||
|
migration=False,
|
||||||
|
*qemu_args
|
||||||
|
)
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.vmm.stop(self.uuid)
|
||||||
|
|
||||||
|
def get_status(self):
|
||||||
|
return self.vmm.get_status(self.uuid)
|
||||||
|
|
||||||
|
def get_vnc_addr(self):
|
||||||
|
return self.vmm.get_vnc(self.uuid)
|
||||||
|
|
||||||
|
def get_uuid(self):
|
||||||
|
return self.uuid
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
success, json = self.vmm.execute_command(uuid, 'query-name')
|
||||||
|
if success:
|
||||||
|
return json['return']['name']
|
||||||
|
|
||||||
|
return None
|
Loading…
Reference in a new issue