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…
	
	Add table
		Add a link
		
	
		Reference in a new issue