Source code for mcvirt.parser

"""Provides argument parser."""

# Copyright (c) 2014 - I.T. Dev Ltd
#
# This file is part of MCVirt.
#
# MCVirt is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# MCVirt is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with MCVirt.  If not, see <http://www.gnu.org/licenses/>

import argparse
import binascii

from mcvirt.exceptions import ArgumentParserException, DrbdVolumeNotInSyncException
from mcvirt.client.rpc import Connection
from mcvirt.system import System
from mcvirt.constants import LockStates
from mcvirt.auth.user_base import UserBase


[docs]class ThrowingArgumentParser(argparse.ArgumentParser): """Override the ArgumentParser class, in order to change the handling of errors."""
[docs] def error(self, message): """Override the error function.""" # Force the argument parser to throw an MCVirt exception on error. raise ArgumentParserException(message)
[docs]class Parser(object): """Provides an argument parser for MCVirt.""" def __init__(self, verbose=True): """Configure the argument parser object.""" self.USERNAME = None self.SESSION_ID = None self.verbose = verbose self.parent_parser = ThrowingArgumentParser(add_help=False) self.parent_parser.add_argument('--username', '-U', dest='username', help='MCVirt username') self.parent_parser.add_argument('--password', dest='password', help='MCVirt password') self.parent_parser.add_argument('--ignore-failed-nodes', dest='ignore_failed_nodes', help='Ignores nodes that are inaccessible', action='store_true') self.parent_parser.add_argument('--accept-failed-nodes-warning', dest='accept_failed_nodes_warning', help=argparse.SUPPRESS, action='store_true') self.parent_parser.add_argument('--ignore-drbd', dest='ignore_drbd', help='Ignores Drbd state', action='store_true') argparser_description = "\nMCVirt - Managed Consistent Virtualisation\n\n" + \ 'Manage the MCVirt host' argparser_epilog = "\nFor more information, see http://mcvirt.itdev.co.uk\n" # Create an argument parser object self.parser = ThrowingArgumentParser(description=argparser_description, epilog=argparser_epilog, formatter_class=argparse.RawDescriptionHelpFormatter) self.subparsers = self.parser.add_subparsers(dest='action', metavar='Action', help='Action to perform') # Add arguments for starting a VM self.start_parser = self.subparsers.add_parser('start', help='Start VM', parents=[self.parent_parser]) self.start_parser.add_argument('--iso', metavar='ISO Name', type=str, help='Path of ISO to attach to VM') self.start_parser.add_argument('vm_name', metavar='VM Name', type=str, help='Name of VM') # Add arguments for stopping a VM self.stop_parser = self.subparsers.add_parser('stop', help='Stop VM', parents=[self.parent_parser]) self.stop_parser.add_argument('vm_name', metavar='VM Name', type=str, help='Name of VM') # Add arguments for resetting a VM self.reset_parser = self.subparsers.add_parser('reset', help='Reset VM', parents=[self.parent_parser]) self.reset_parser.add_argument('vm_name', metavar='VM Name', type=str, help='Name of VM') # Add arguments for fixing deadlock on a vm self.method_lock_parser = self.subparsers.add_parser( 'clear-method-lock', help='Resolve the lock of a call to a method on the MCVirt daemon.', parents=[self.parent_parser] ) # Add arguments for ISO functions self.iso_parser = self.subparsers.add_parser('iso', help='ISO managment', parents=[self.parent_parser]) self.iso_parser.add_argument('--list', dest='list', action='store_true', help='List available ISOs') self.iso_parser.add_argument('--add-from-path', dest='add_path', help='Copy an ISO to ISO directory', metavar='PATH') self.iso_parser.add_argument('--delete', dest='delete_path', help='Delete an ISO', metavar='NAME') self.iso_parser.add_argument('--add-from-url', dest='add_url', help='Download and add an ISO', metavar='URL') # Add arguments for managing users self.user_parser = self.subparsers.add_parser('user', help='User managment', parents=[self.parent_parser]) self.user_subparser = self.user_parser.add_subparsers( dest='user_action', help='User managment action to perform', metavar='Action' ) self.change_password_subparser = self.user_subparser.add_parser( 'change-password', help='Change a user password', parents=[self.parent_parser] ) self.change_password_subparser.add_argument( '--new-password', dest='new_password', metavar='New password', help='The new password' ) self.change_password_subparser.add_argument( '--target-user', dest='target_user', metavar='Target user', help='The user to change the password of' ) self.create_user_subparser = self.user_subparser.add_parser( 'create', help='Create a new user', parents=[self.parent_parser] ) self.create_user_subparser.add_argument( 'new_username', metavar='User', type=str, help='The new user to create' ) self.create_user_mut_ex_group = self.create_user_subparser.add_mutually_exclusive_group( required=False ) self.create_user_mut_ex_group.add_argument( '--user-password', dest='new_user_password', metavar='New password', help='The password for the new user' ) self.create_user_mut_ex_group.add_argument( '--generate-password', dest='generate_password', action='store_true', help='Generate a password for the new user' ) self.remove_user_subparser = self.user_subparser.add_parser( 'remove', help='Remove a user', parents=[self.parent_parser] ) self.remove_user_subparser.add_argument( 'remove_username', metavar='User', type=str, help='The user to remove' ) # Add arguments for creating a VM self.create_parser = self.subparsers.add_parser('create', help='Create VM', parents=[self.parent_parser]) self.create_parser.add_argument('--memory', dest='memory', metavar='Memory', required=True, type=int, help='Amount of memory to allocate to the VM (MiB)') self.create_parser.add_argument('--disk-size', dest='disk_size', metavar='Disk Size', type=int, default=None, help='Size of disk to be created for the VM (MB)') self.create_parser.add_argument( '--cpu-count', dest='cpu_count', metavar='CPU Count', help='Number of virtual CPU cores to be allocated to the VM', type=int, required=True ) self.create_parser.add_argument( '--network', dest='networks', metavar='Network Connection', type=str, action='append', help='Name of networks to connect VM to (each network has a separate NIC)' ) self.create_parser.add_argument('--nodes', dest='nodes', action='append', help='Specify the nodes that the VM will be' + ' hosted on, if a Drbd storage-type' + ' is specified', default=[]) self.create_parser.add_argument('vm_name', metavar='VM Name', type=str, help='Name of VM') # Determine if machine is configured to use Drbd self.create_parser.add_argument('--storage-type', dest='storage_type', metavar='Storage backing type', type=str, default=None, choices=['Local', 'Drbd']) self.create_parser.add_argument('--driver', metavar='Hard Drive Driver', dest='hard_disk_driver', type=str, help='Driver for hard disk', default=None) # Get arguments for deleting a VM self.delete_parser = self.subparsers.add_parser('delete', help='Delete VM', parents=[self.parent_parser]) self.delete_parser.add_argument('--remove-data', dest='remove_data', action='store_true', help='Removes the VM data from the host') self.delete_parser.add_argument('vm_name', metavar='VM Name', type=str, help='Name of VM') # Get arguments for registering a VM self.register_parser = self.subparsers.add_parser('register', help='Registers a VM on' + ' the local node', parents=[self.parent_parser]) self.register_parser.add_argument('vm_name', metavar='VM Name', type=str, help='Name of VM') # Get arguments for unregistering a VM self.unregister_parser = self.subparsers.add_parser('unregister', help='Unregisters a VM from' + ' the local node', parents=[self.parent_parser]) self.unregister_parser.add_argument('vm_name', metavar='VM Name', type=str, help='Name of VM') # Get arguments for updating a VM self.update_parser = self.subparsers.add_parser('update', help='Update VM Configuration', parents=[self.parent_parser]) self.update_parser.add_argument('--memory', dest='memory', metavar='Memory', type=int, help='Amount of memory to allocate to the VM (MiB)') self.update_parser.add_argument( '--cpu-count', dest='cpu_count', metavar='CPU Count', type=int, help='Number of virtual CPU cores to be allocated to the VM' ) self.update_parser.add_argument( '--add-network', dest='add_network', metavar='Add Network', type=str, help='Adds a NIC to the VM, connected to the given network' ) self.update_parser.add_argument( '--remove-network', dest='remove_network', metavar='Remove Network', type=str, help='Removes a NIC from VM with the given MAC-address (e.g. \'00:00:00:00:00:00)\'' ) self.update_parser.add_argument('--add-disk', dest='add_disk', metavar='Add Disk', type=int, help='Add disk to the VM (size in MB)') self.update_parser.add_argument('--storage-type', dest='storage_type', metavar='Storage backing type', type=str, default=None) self.update_parser.add_argument('--driver', metavar='Hard Drive Driver', dest='hard_disk_driver', type=str, help='Driver for hard disk', default=None) self.update_parser.add_argument('--increase-disk', dest='increase_disk', metavar='Increase Disk', type=int, help='Increases VM disk by provided amount (MB)') self.update_parser.add_argument('--disk-id', dest='disk_id', metavar='Disk Id', type=int, help='The ID of the disk to be increased by') self.update_parser.add_argument('--attach-iso', '--iso', dest='iso', metavar='ISO Name', type=str, help=('Attach an ISO to a running VM.' ' Specify without value to detach ISO.')) self.update_parser.add_argument('vm_name', metavar='VM Name', type=str, help='Name of VM') # Get arguments for making permission changes to a VM self.permission_parser = self.subparsers.add_parser( 'permission', help='Update user permissions', parents=[self.parent_parser] ) self.permission_parser.add_argument( '--add-user', dest='add_user', metavar='Add user to user group', type=str, help='Adds a given user to a VM, allowing them to perform basic functions.' ) self.permission_parser.add_argument( '--delete-user', dest='delete_user', metavar='Remove user from user group', type=str, help='Removes a given user from a VM. This prevents them to perform basic functions.' ) self.permission_parser.add_argument( '--add-owner', dest='add_owner', metavar='Add user to owner group', type=str, help=('Adds a given user as an owner to a VM, ' 'allowing them to perform basic functions and manager users.') ) self.permission_parser.add_argument( '--delete-owner', dest='delete_owner', metavar='Remove user from owner group', type=str, help=('Removes a given owner from a VM. ' 'This prevents them to perform basic functions and manager users.') ) self.permission_parser.add_argument( '--add-superuser', dest='add_superuser', metavar='Add user to superuser group', type=str, help=('Adds a given user to the global superuser role. ' 'This allows the user to completely manage the MCVirt node/cluster') ) self.permission_parser.add_argument( '--delete-superuser', dest='delete_superuser', metavar='Removes user from the superuser group', type=str, help='Removes a given user from the superuser group' ) self.permission_target_group = self.permission_parser.add_mutually_exclusive_group( required=True ) self.permission_target_group.add_argument('vm_name', metavar='VM Name', type=str, help='Name of VM', nargs='?') self.permission_target_group.add_argument('--global', dest='global', action='store_true', help='Set a global MCVirt permission') # Create subparser for network-related commands self.network_parser = self.subparsers.add_parser( 'network', help='Manage the virtual networks on the MCVirt host', parents=[self.parent_parser] ) self.network_subparser = self.network_parser.add_subparsers( dest='network_action', metavar='Action', help='Action to perform on the network' ) self.network_create_parser = self.network_subparser.add_parser( 'create', help='Create a network on the MCVirt host', parents=[self.parent_parser] ) self.network_create_parser.add_argument( '--interface', dest='interface', metavar='Interface', type=str, required=True, help='Physical interface on the system to bridge to the virtual network' ) self.network_create_parser.add_argument('network', metavar='Network Name', type=str, help='Name of the virtual network to be created') self.network_delete_parser = self.network_subparser.add_parser( 'delete', help='Delete a network on the MCVirt host', parents=[self.parent_parser] ) self.network_delete_parser.add_argument('network', metavar='Network Name', type=str, help='Name of the virtual network to be removed') self.network_subparser.add_parser('list', help='List the networks on the node', parents=[self.parent_parser]) # Get arguments for getting VM information self.info_parser = self.subparsers.add_parser('info', help='View VM information', parents=[self.parent_parser]) self.info_mutually_exclusive_group = self.info_parser.add_mutually_exclusive_group( required=False ) self.info_mutually_exclusive_group.add_argument( '--vnc-port', dest='vnc_port', help='Displays the port that VNC is being hosted from', action='store_true' ) self.info_mutually_exclusive_group.add_argument( '--node', dest='node', help='Displays which node that the VM is currently registered on', action='store_true' ) self.info_parser.add_argument('vm_name', metavar='VM Name', type=str, help='Name of VM', nargs='?', default=None) # Get arguments for listing VMs self.list_parser = self.subparsers.add_parser('list', help='List VMs present on host', parents=[self.parent_parser]) # Get arguments for cloning a VM self.clone_parser = self.subparsers.add_parser('clone', help='Clone a VM', parents=[self.parent_parser]) self.clone_parser.add_argument('--template', dest='template', type=str, required=True, metavar='Parent VM', help='The name of the VM to clone from') self.clone_parser.add_argument('vm_name', metavar='VM Name', type=str, help='Name of VM') # Get arguments for cloning a VM self.duplicate_parser = self.subparsers.add_parser('duplicate', help='Duplicate a VM', parents=[self.parent_parser]) self.duplicate_parser.add_argument('--template', dest='template', metavar='Parent VM', type=str, required=True, help='The name of the VM to duplicate') self.duplicate_parser.add_argument('vm_name', metavar='VM Name', type=str, help='Name of duplicate VM') # Get arguments for migrating a VM self.migrate_parser = self.subparsers.add_parser( 'migrate', help='Perform migrations of virtual machines', parents=[self.parent_parser] ) self.migrate_parser.add_argument( '--node', dest='destination_node', metavar='Destination Node', type=str, required=True, help='The name of the destination node for the VM to be migrated to' ) self.migrate_parser.add_argument( '--online', dest='online_migration', help='Perform an online-migration', action='store_true' ) self.migrate_parser.add_argument( '--start-after-migration', dest='start_after_migration', help='Causes the VM to be booted after the migration', action='store_true' ) self.migrate_parser.add_argument( '--wait-for-shutdown', dest='wait_for_shutdown', help='Waits for the VM to shutdown before performing the migration', action='store_true' ) self.migrate_parser.add_argument('vm_name', metavar='VM Name', type=str, help='Name of VM') # Create sub-parser for moving VMs self.move_parser = self.subparsers.add_parser('move', help=('Move a VM and related storage' ' to another node'), parents=[self.parent_parser]) self.move_parser.add_argument('--source-node', dest='source_node', help="The node that the VM will be moved from.\n" + 'For Drbd VMs, the source node must not be' + " the local node.\nFor Local VMs, the node" + " must be the local node, but may be omitted.") self.move_parser.add_argument('--destination-node', dest='destination_node', help='The node that the VM will be moved to') self.move_parser.add_argument('vm_name', metavar='VM Name', type=str, help='Name of VM') # Create sub-parser for cluster-related commands self.cluster_parser = self.subparsers.add_parser( 'cluster', help='Manage an MCVirt cluster and the connected nodes', parents=[self.parent_parser] ) self.cluster_subparser = self.cluster_parser.add_subparsers( dest='cluster_action', metavar='Action', help='Action to perform on the cluster' ) self.connection_string_subparser = self.cluster_subparser.add_parser( 'get-connect-string', help='Generates a connection string to add the node to a cluster', parents=[self.parent_parser] ) self.node_add_parser = self.cluster_subparser.add_parser( 'add-node', help='Adds a node to the MCVirt cluster', parents=[self.parent_parser]) self.node_add_parser.add_argument( '--connect-string', dest='connect_string', metavar='node', type=str, required=True, help='Connect string from the target node') self.node_remove_parser = self.cluster_subparser.add_parser( 'remove-node', help='Removes a node to the MCVirt cluster', parents=[self.parent_parser] ) self.node_remove_parser.add_argument( '--node', dest='node', metavar='node', type=str, required=True, help='Hostname of the remote node to remove from the cluster') # Create subparser for commands relating to the local node configuration self.node_parser = self.subparsers.add_parser( 'node', help='Modify configurations relating to the local node', parents=[self.parent_parser] ) self.node_parser.add_argument('--set-vm-vg', dest='volume_group', metavar='VM Volume Group', help=('Sets the local volume group used for Virtual' ' machine HDD logical volumes')) self.node_parser.add_argument('--set-ip-address', dest='ip_address', metavar='Cluster IP Address', help=('Sets the cluster IP address for the local node,' ' used for Drbd and cluster management.')) # Create sub-parser for VM verification self.verify_parser = self.subparsers.add_parser( 'verify', help='Perform verification of VMs', parents=[ self.parent_parser]) self.verify_mutual_exclusive_group = self.verify_parser.add_mutually_exclusive_group( required=True ) self.verify_mutual_exclusive_group.add_argument('--all', dest='all', action='store_true', help='Verifies all of the VMs') self.verify_mutual_exclusive_group.add_argument('vm_name', metavar='VM Name', nargs='?', help='Specify a single VM to verify') # Create sub-parser for Drbd-related commands self.drbd_parser = self.subparsers.add_parser('drbd', help='Manage Drbd clustering', parents=[self.parent_parser]) self.drbd_mutually_exclusive_group = self.drbd_parser.add_mutually_exclusive_group( required=True ) self.drbd_mutually_exclusive_group.add_argument( '--enable', dest='enable', action='store_true', help='Enable Drbd support on the cluster' ) self.drbd_mutually_exclusive_group.add_argument( '--list', dest='list', action='store_true', help='List Drbd volumes on the system' ) # Create sub-parser for backup commands self.backup_parser = self.subparsers.add_parser('backup', help='Performs backup-related tasks', parents=[self.parent_parser]) self.backup_mutual_exclusive_group = self.backup_parser.add_mutually_exclusive_group( required=True ) self.backup_mutual_exclusive_group.add_argument( '--create-snapshot', dest='create_snapshot', help='Enable Drbd support on the cluster', action='store_true' ) self.backup_mutual_exclusive_group.add_argument( '--delete-snapshot', dest='delete_snapshot', help='Enable Drbd support on the cluster', action='store_true' ) self.backup_parser.add_argument( '--disk-id', dest='disk_id', metavar='Disk Id', type=int, required=True, help='The ID of the disk to manage the backup snapshot of' ) self.backup_parser.add_argument('vm_name', metavar='VM Name', type=str, help='Name of VM') # Create sub-parser for managing VM locks self.lock_parser = self.subparsers.add_parser('lock', help='Perform verification of VMs', parents=[self.parent_parser]) self.lock_mutual_exclusive_group = self.lock_parser.add_mutually_exclusive_group( required=True ) self.lock_mutual_exclusive_group.add_argument('--check-lock', dest='check_lock', help='Checks the lock status of a VM', action='store_true') self.lock_mutual_exclusive_group.add_argument('--lock', dest='lock', help='Locks a VM', action='store_true') self.lock_mutual_exclusive_group.add_argument('--unlock', dest='unlock', help='Unlocks a VM', action='store_true') self.lock_parser.add_argument('vm_name', metavar='VM Name', type=str, help='Name of VM') self.exit_parser = self.subparsers.add_parser('exit', help='Exits the MCVirt shell', parents=[self.parent_parser])
[docs] def print_status(self, status): """Print if the user has specified that the parser should print statuses.""" if self.verbose: print status
[docs] def parse_arguments(self, script_args=None): """Parse arguments and performs actions based on the arguments.""" # If arguments have been specified, split, so that # an array is sent to the argument parser if (script_args is not None): script_args = script_args.split() args = self.parser.parse_args(script_args) action = args.action ignore_cluster = False if args.ignore_failed_nodes: # If the user has specified to ignore the cluster, # print a warning and confirm the user's answer if not args.accept_failed_nodes_warning: self.print_status(('WARNING: Running MCVirt with --ignore-failed-nodes' ' can leave the cluster in an inconsistent state!')) continue_answer = System.getUserInput('Would you like to continue? (Y/n): ') if continue_answer.strip() is not 'Y': self.print_status('Cancelled...') return ignore_cluster = True # Obtain connection to Pyro server if self.SESSION_ID and self.USERNAME: rpc = Connection(username=self.USERNAME, session_id=self.SESSION_ID, ignore_cluster=ignore_cluster) else: # Check if user/password have been passed. Else, ask for them. username = args.username if args.username else System.getUserInput( 'Username: ' ).rstrip() if args.password: password = args.password else: password = System.getUserInput( 'Password: ', password=True ).rstrip() rpc = Connection(username=username, password=password, ignore_cluster=ignore_cluster) self.SESSION_ID = rpc.session_id self.USERNAME = username if args.ignore_drbd: rpc.ignore_drbd() # Perform functions on the VM based on the action passed to the script if action == 'start': vm_factory = rpc.get_connection('virtual_machine_factory') vm_object = vm_factory.getVirtualMachineByName(args.vm_name) rpc.annotate_object(vm_object) if args.iso: iso_factory = rpc.get_connection('iso_factory') iso_object = iso_factory.get_iso_by_name(args.iso) rpc.annotate_object(iso_object) else: iso_object = None vm_object.start(iso_object=iso_object) self.print_status('Successfully started VM') elif action == 'stop': vm_factory = rpc.get_connection('virtual_machine_factory') vm_object = vm_factory.getVirtualMachineByName(args.vm_name) rpc.annotate_object(vm_object) vm_object.stop() self.print_status('Successfully stopped VM') elif action == 'reset': vm_factory = rpc.get_connection('virtual_machine_factory') vm_object = vm_factory.getVirtualMachineByName(args.vm_name) rpc.annotate_object(vm_object) vm_object.reset() self.print_status('Successfully reset VM') elif action == 'clear-method-lock': node = rpc.get_connection('node') if node.clear_method_lock(): self.print_status('Successfully cleared method lock') else: self.print_status('method lock already cleared') elif action == 'create': storage_type = args.storage_type or None # Convert memory allocation from MiB to KiB memory_allocation = int(args.memory) * 1024 vm_factory = rpc.get_connection('virtual_machine_factory') hard_disks = [args.disk_size] if args.disk_size is not None else [] vm_object = vm_factory.create( name=args.vm_name, cpu_cores=args.cpu_count, memory_allocation=memory_allocation, hard_drives=hard_disks, network_interfaces=args.networks, storage_type=storage_type, hard_drive_driver=args.hard_disk_driver, available_nodes=args.nodes) elif action == 'delete': vm_factory = rpc.get_connection('virtual_machine_factory') vm_object = vm_factory.getVirtualMachineByName(args.vm_name) rpc.annotate_object(vm_object) vm_object.delete(args.remove_data) elif action == 'register': vm_factory = rpc.get_connection('virtual_machine_factory') vm_object = vm_factory.getVirtualMachineByName(args.vm_name) rpc.annotate_object(vm_object) vm_object.register() elif action == 'unregister': vm_factory = rpc.get_connection('virtual_machine_factory') vm_object = vm_factory.getVirtualMachineByName(args.vm_name) rpc.annotate_object(vm_object) vm_object.unregister() elif action == 'update': vm_factory = rpc.get_connection('virtual_machine_factory') vm_object = vm_factory.getVirtualMachineByName(args.vm_name) rpc.annotate_object(vm_object) if args.memory: old_ram_allocation_kib = vm_object.getRAM() old_ram_allocation = int(old_ram_allocation_kib) / 1024 new_ram_allocation = int(args.memory) * 1024 vm_object.updateRAM(new_ram_allocation, old_value=old_ram_allocation_kib) self.print_status( 'RAM allocation will be changed from %sMiB to %sMiB.' % (old_ram_allocation, args.memory) ) if args.cpu_count: old_cpu_count = vm_object.getCPU() vm_object.updateCPU(args.cpu_count, old_value=old_cpu_count) self.print_status( 'Number of virtual cores will be changed from %s to %s.' % (old_cpu_count, args.cpu_count) ) if args.remove_network: network_adapter_factory = rpc.get_connection('network_adapter_factory') network_adapter_object = network_adapter_factory.getNetworkAdapterByMacAdress( vm_object, args.remove_network ) rpc.annotate_object(network_adapter_object) network_adapter_object.delete() if (args.add_network): network_factory = rpc.get_connection('network_factory') network_adapter_factory = rpc.get_connection('network_adapter_factory') network_object = network_factory.get_network_by_name(args.add_network) rpc.annotate_object(network_object) network_adapter_factory.create(vm_object, network_object) if args.add_disk: hard_drive_factory = rpc.get_connection('hard_drive_factory') hard_drive_factory.create(vm_object, size=args.add_disk, storage_type=args.storage_type, driver=args.hard_disk_driver) if (args.increase_disk and args.disk_id): hard_drive_factory = rpc.get_connection('hard_drive_factory') hard_drive_object = hard_drive_factory.getObject(vm_object, args.disk_id) rpc.annotate_object(hard_drive_object) hard_drive_object.increaseSize(args.increase_disk) if args.iso: iso_factory = rpc.get_connection('iso_factory') iso_object = iso_factory.get_iso_by_name(args.iso) rpc.annotate_object(iso_object) disk_drive = vm_object.get_disk_drive() rpc.annotate_object(disk_drive) disk_drive.attachISO(iso_object, True) elif action == 'permission': if (args.add_superuser or args.delete_superuser) and args.vm_name: raise ArgumentParserException('Superuser groups are global-only roles') if args.vm_name: vm_factory = rpc.get_connection('virtual_machine_factory') vm_object = vm_factory.getVirtualMachineByName(args.vm_name) rpc.annotate_object(vm_object) permission_destination_string = 'role on VM %s' % vm_object.get_name() else: vm_object = None permission_destination_string = 'global role' auth_object = rpc.get_connection('auth') rpc.annotate_object(auth_object) user_factory = rpc.get_connection('user_factory') rpc.annotate_object(user_factory) if args.add_user: user_object = user_factory.get_user_by_username(args.add_user) rpc.annotate_object(user_object) auth_object.add_user_permission_group( permission_group='user', user_object=user_object, vm_object=vm_object) self.print_status( 'Successfully added \'%s\' to \'user\' %s' % (args.add_user, permission_destination_string)) if args.delete_user: user_object = user_factory.get_user_by_username(args.delete_user) rpc.annotate_object(user_object) auth_object.delete_user_permission_group( permission_group='user', user_object=user_object, vm_object=vm_object) self.print_status( 'Successfully removed \'%s\' from \'user\' %s' % (args.delete_user, permission_destination_string)) if args.add_owner: user_object = user_factory.get_user_by_username(args.add_owner) rpc.annotate_object(user_object) auth_object.add_user_permission_group( permission_group='owner', user_object=user_object, vm_object=vm_object) self.print_status( 'Successfully added \'%s\' to \'owner\' %s' % (args.add_owner, permission_destination_string)) if args.delete_owner: user_object = user_factory.get_user_by_username(args.delete_owner) rpc.annotate_object(user_object) auth_object.delete_user_permission_group( permission_group='owner', user_object=user_object, vm_object=vm_object) self.print_status( 'Successfully removed \'%s\' from \'owner\' %s' % (args.delete_owner, permission_destination_string)) if args.add_superuser: user_object = user_factory.get_user_by_username(args.add_superuser) rpc.annotate_object(user_object) auth_object.add_superuser(user_object=user_object) self.print_status('Successfully added %s to the global superuser group' % args.add_superuser) if args.delete_superuser: user_object = user_factory.get_user_by_username(args.delete_superuser) rpc.annotate_object(user_object) auth_object.delete_superuser(user_object=user_object) self.print_status('Successfully removed %s from the global superuser group ' % args.delete_superuser) elif action == 'info': if not args.vm_name and (args.vnc_port or args.node): self.parser.error('Must provide a VM Name') if args.vm_name: vm_factory = rpc.get_connection('virtual_machine_factory') vm_object = vm_factory.getVirtualMachineByName(args.vm_name) rpc.annotate_object(vm_object) if args.vnc_port: self.print_status(vm_object.getVncPort()) elif args.node: self.print_status(vm_object.getNode()) else: self.print_status(vm_object.getInfo()) else: cluster_object = rpc.get_connection('cluster') self.print_status(cluster_object.print_info()) elif action == 'network': network_factory = rpc.get_connection('network_factory') if args.network_action == 'create': network_factory.create(args.network, physical_interface=args.interface) elif args.network_action == 'delete': network_object = network_factory.get_network_by_name(args.network) rpc.annotate_object(network_object) network_object.delete() elif args.network_action == 'list': self.print_status(network_factory.get_network_list_table()) elif action == 'migrate': vm_factory = rpc.get_connection('virtual_machine_factory') vm_object = vm_factory.getVirtualMachineByName(args.vm_name) rpc.annotate_object(vm_object) if args.online_migration: vm_object.onlineMigrate(args.destination_node) else: vm_object.offlineMigrate( args.destination_node, wait_for_vm_shutdown=args.wait_for_shutdown, start_after_migration=args.start_after_migration ) self.print_status('Successfully migrated \'%s\' to %s' % (vm_object.get_name(), args.destination_node)) elif action == 'move': vm_factory = rpc.get_connection('virtual_machine_factory') vm_object = vm_factory.getVirtualMachineByName(args.vm_name) rpc.annotate_object(vm_object) vm_object.move(destination_node=args.destination_node, source_node=args.source_node) elif action == 'cluster': cluster_object = rpc.get_connection('cluster') if args.cluster_action == 'get-connect-string': self.print_status(cluster_object.get_connection_string()) if args.cluster_action == 'add-node': if args.connect_string: connect_string = args.connect_string else: connect_string = System.getUserInput('Enter Connect String: ') cluster_object.add_node(connect_string) self.print_status('Successfully added node') if args.cluster_action == 'remove-node': cluster_object.remove_node(args.node) self.print_status('Successfully removed node %s' % args.node) elif action == 'node': node = rpc.get_connection('node') if args.volume_group: node.set_storage_volume_group(args.volume_group) self.print_status('Successfully set VM storage volume group to %s' % args.volume_group) if args.ip_address: node.set_cluster_ip_address(args.ip_address) self.print_status('Successfully set cluster IP address to %s' % args.ip_address) elif action == 'verify': vm_factory = rpc.get_connection('virtual_machine_factory') if args.vm_name: vm_object = vm_factory.getVirtualMachineByName(args.vm_name) rpc.annotate_object(vm_object) vm_objects = [vm_object] elif args.all: vm_objects = vm_factory.getAllVirtualMachines() # Iterate over the VMs and check each disk failures = [] for vm_object in vm_objects: rpc.annotate_object(vm_object) for disk_object in vm_object.getHardDriveObjects(): rpc.annotate_object(disk_object) if disk_object.get_type() == 'Drbd': # Catch any exceptions due to the Drbd volume not being in-sync try: disk_object.verify() self.print_status( ('Drbd verification for %s (%s) completed ' 'without out-of-sync blocks') % (disk_object.resource_name, vm_object.get_name()) ) except DrbdVolumeNotInSyncException, e: # Append the not-in-sync exception message to an array, # so the rest of the disks can continue to be checked failures.append(e.message) # If there were any failures during the verification, raise the exception and print # all exception messages if failures: raise DrbdVolumeNotInSyncException("\n".join(failures)) elif action == 'drbd': node_drbd = rpc.get_connection('node_drbd') if args.enable: node_drbd.enable() if (args.list): self.print_status(node_drbd.list()) elif action == 'backup': vm_factory = rpc.get_connection('virtual_machine_factory') vm_object = vm_factory.getVirtualMachineByName(args.vm_name) rpc.annotate_object(vm_object) hard_drive_factory = rpc.get_connection('hard_drive_factory') hard_drive_object = hard_drive_factory.getObject(vm_object, args.disk_id) rpc.annotate_object(hard_drive_object) if args.create_snapshot: self.print_status(hard_drive_object.createBackupSnapshot()) elif (args.delete_snapshot): hard_drive_object.deleteBackupSnapshot() elif action == 'lock': vm_factory = rpc.get_connection('virtual_machine_factory') vm_object = vm_factory.getVirtualMachineByName(args.vm_name) rpc.annotate_object(vm_object) if args.lock: vm_object.setLockState(LockStates.LOCKED.value) if args.unlock: vm_object.setLockState(LockStates.UNLOCKED.value) if args.check_lock: self.print_status(LockStates(vm_object.getLockState()).name) elif action == 'clone': vm_factory = rpc.get_connection('virtual_machine_factory') vm_object = vm_factory.getVirtualMachineByName(args.template) rpc.annotate_object(vm_object) vm_object.clone(args.vm_name) elif action == 'duplicate': vm_factory = rpc.get_connection('virtual_machine_factory') vm_object = vm_factory.getVirtualMachineByName(args.template) rpc.annotate_object(vm_object) vm_object.duplicate(args.vm_name) elif action == 'list': vm_factory = rpc.get_connection('virtual_machine_factory') self.print_status(vm_factory.listVms()) elif action == 'iso': iso_factory = rpc.get_connection('iso_factory') if args.list: self.print_status(iso_factory.get_iso_list()) if args.add_path: iso_writer = iso_factory.add_iso_from_stream(args.add_path) rpc.annotate_object(iso_writer) with open(args.add_path, 'rb') as iso_fh: while True: data_chunk = iso_fh.read(1024) if data_chunk: data_chunk = binascii.hexlify(data_chunk) iso_writer.write_data(data_chunk) else: break iso_object = iso_writer.write_end() rpc.annotate_object(iso_object) self.print_status('Successfully added ISO: %s' % iso_object.get_name()) if args.add_url: iso_object = iso_factory.add_from_url(args.add_url) rpc.annotate_object(iso_object) self.print_status('Successfully added ISO: %s' % iso_object.get_name()) if args.delete_path: iso_object = iso_factory.get_iso_by_name(args.delete_path) rpc.annotate_object(iso_object) iso_object.delete() self.print_status('Successfully removed iso: %s' % args.delete_path) elif action == 'user': if args.user_action == 'change-password': user_factory = rpc.get_connection('user_factory') target_user = args.target_user or self.USERNAME user = user_factory.get_user_by_username(target_user) rpc.annotate_object(user) new_password = args.new_password or System.getNewPassword() user.set_password(new_password) elif args.user_action == 'create': user_factory = rpc.get_connection('user_factory') if args.generate_password: new_password = UserBase.generate_password(10) else: new_password = args.new_user_password or System.getNewPassword() user_factory.create(args.new_username, new_password) self.print_status('New user details:\nUsername: %s' % args.new_username) if args.generate_password: self.print_status('Password: %s' % new_password) elif args.user_action == 'remove': user_factory = rpc.get_connection('user_factory') user = user_factory.get_user_by_username(args.remove_username) rpc.annotate_object(user) user.delete()