def add_node_configuration(self, node_name, ip_address, connection_user, connection_password, ca_key): """Add MCVirt node to configuration, generates a cluster user on the remote node and stores credentials against node in the MCVirt configuration. """ self._get_registered_object('auth').assert_permission( PERMISSIONS.MANAGE_CLUSTER) # Create CA file ssl_object = self._get_registered_object( 'certificate_generator_factory').get_cert_generator(node_name) ssl_object.ca_pub_file = ca_key # Connect to node and obtain cluster user remote = Connection(username=connection_user, password=connection_password, host=node_name) remote_user_factory = remote.get_connection('user_factory') connection_user = remote_user_factory.get_user_by_username( connection_user) remote.annotate_object(connection_user) username, password = connection_user.create_cluster_user( host=get_hostname()) # Add node to configuration file def add_node_config(mcvirt_config): mcvirt_config['cluster']['nodes'][node_name] = { 'ip_address': ip_address, 'username': username, 'password': password } MCVirtConfig().update_config(add_node_config)
def add_node_configuration(self, node_name, ip_address, connection_user, connection_password, ca_key): """Add MCVirt node to configuration, generates a cluster user on the remote node and stores credentials against node in the MCVirt configuration. """ self._get_registered_object('auth').assert_permission(PERMISSIONS.MANAGE_CLUSTER) # Create CA file ssl_object = self._get_registered_object( 'certificate_generator_factory').get_cert_generator(node_name) ssl_object.ca_pub_file = ca_key # Connect to node and obtain cluster user remote = Connection(username=connection_user, password=connection_password, host=node_name) remote_user_factory = remote.get_connection('user_factory') connection_user = remote_user_factory.get_user_by_username(connection_user) remote.annotate_object(connection_user) username, password = connection_user.create_cluster_user(host=get_hostname()) # Add node to configuration file def add_node_config(mcvirt_config): mcvirt_config['cluster']['nodes'][node_name] = { 'ip_address': ip_address, 'username': username, 'password': password } MCVirtConfig().update_config(add_node_config)
def setUp(self): """Obtain connections to the daemon and create various member variables. """ # Create and store RPC connection to daemon. self.rpc = Connection(self.RPC_USERNAME, self.RPC_PASSWORD) # Create and store parser instance self.parser = Parser(verbose=False) # Obtain the session ID from the RPC connection and re-use this, # so that the parser does not need to authenticate with a password # self.parser.parse_arguments('list --username %s --password %s' % (self.RPC_USERNAME, # self.RPC_PASSWORD)) self.parser.USERNAME = self.RPC_USERNAME self.parser.SESSION_ID = self.rpc.session_id # Setup variable for test VM self.test_vms = \ { 'TEST_VM_1': { 'name': 'mcvirt-unittest-vm', 'cpu_count': 1, 'memory_allocation': 100, 'disk_size': [100], 'networks': ['Production'] }, 'TEST_VM_2': { 'name': 'mcvirt-unittest-vm2', 'cpu_count': 2, 'memory_allocation': 120, 'disk_size': [100], 'networks': ['Production'] } } # Ensure any test VM is stopped and removed from the machine self.stop_and_delete(self.test_vms['TEST_VM_2']['name']) self.stop_and_delete(self.test_vms['TEST_VM_1']['name']) self.vm_factory = self.rpc.get_connection('virtual_machine_factory') self.test_network_name = 'testnetwork' self.test_physical_interface = 'vmbr0' self.network_factory = self.rpc.get_connection('network_factory') # Determine if the test network exists. If so, delete it if self.network_factory.check_exists(self.test_network_name): network = self.network_factory.get_network_by_name( self.test_network_name) self.rpc.annotate_object(network) network.delete()
def start(self): """Start the daemon, run the unit tests and tear down""" try: # Attempt to start daemon self.daemon_thread.start() # Attempt to run tests success = self.runner.run(self.all_tests).wasSuccessful() finally: # Set the run condition flag for daemon to False in order to # stop on next loop self.daemon_run = False OnlineMigrateTests.RPC_DAEMON = None try: # Perform final connection to daemon to ensure that it loops # to stop. Connection(username='******', password='******') except: pass # Wait for daemon to stop self.daemon_thread.join() # Return success state of tests return success
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) ignore_cluster = self.check_ignore_failed(args) if self.session_id and self.username: self.rpc = Connection(username=self.username, session_id=self.session_id, ignore_cluster=ignore_cluster) else: # Obtain connection to Pyro server if not (args.password or args.username): self.authenticate_saved_session(ignore_cluster) if not self.rpc: self.authenticate_username_password(args, ignore_cluster) self.store_cached_session(args) if args.ignore_drbd: self.rpc.ignore_drbd() # If a custom parser function has been defined, used this and exit # instead of running through (old) main parser workflow if 'func' in dir(args): args.func(args=args, p_=self) else: raise ArgumentParserException('No handler registered for parser')
def authenticate_saved_session(self, ignore_cluster): """Attempt to authenticate using saved session""" # Try logging in with saved session auth_session = None try: with open(self.auth_cache_file, 'r') as cache_fh: auth_username = cache_fh.readline().strip() auth_session = cache_fh.readline().strip() except IOError: pass if auth_session: try: self.rpc = Connection(username=auth_username, session_id=auth_session, ignore_cluster=ignore_cluster) self.session_id = self.rpc.session_id self.username = self.rpc.username except AuthenticationError: # If authentication fails with cached session, # print error, attempt to remove sessionn file and # remove rpc connection self.print_status('Authentication error occured when using saved session.') try: os.remove(self.auth_cache_file) except OSError: pass self.rpc = None
def test_add_delete_superuser(self): """Add/delete a user to/from the superuser role""" # Assert that the user is not already a superuser self.assertFalse( self.TEST_USERNAME in self.RPC_DAEMON.DAEMON.registered_factories['auth'].get_superusers() ) # Add the user to the superuser group using the argument parser self.parser.parse_arguments('permission --add-superuser %s --global' % self.TEST_USERNAME) # Ensure that the auth object asserts that the user is a superuser self.assertTrue( self.TEST_USERNAME in self.RPC_DAEMON.DAEMON.registered_factories['auth'].get_superusers() ) rpc_connection = Connection(username=self.TEST_USERNAME, password=self.TEST_PASSWORD) test_auth = rpc_connection.get_connection('auth') self.assertTrue(test_auth.is_superuser()) # Ensure that user can start a test VM and delete it test_vm = self.create_vm('TEST_VM_1', 'Local') self.parse_command('start %s' % test_vm.get_name(), username=self.TEST_USERNAME, password=self.TEST_PASSWORD) self.parse_command('stop %s' % test_vm.get_name(), username=self.TEST_USERNAME, password=self.TEST_PASSWORD) self.parse_command('delete --delete-data %s' % test_vm.get_name(), username=self.TEST_USERNAME, password=self.TEST_PASSWORD) # Delete the user from the superuser group using the argument parser self.parser.parse_arguments('permission --delete-superuser %s --global' % self.TEST_USERNAME) # Assert that the user is no longer considered a superuser self.assertFalse(test_auth.is_superuser()) # Assert that the user no longer has access to the superuser permission self.assertFalse(test_auth.is_superuser()) self.assertFalse( self.TEST_USERNAME in self.RPC_DAEMON.DAEMON.registered_factories['auth'].get_superusers() )
def test_add_delete_superuser(self): """Add/delete a user to/from the superuser role""" # Assert that the user is not already a superuser self.assertFalse(self.TEST_USERNAME in self.RPC_DAEMON.DAEMON. registered_factories['auth'].get_superusers()) # Add the user to the superuser group using the argument parser self.parser.parse_arguments('permission --add-superuser %s --global' % self.TEST_USERNAME) # Ensure that the auth object asserts that the user is a superuser self.assertTrue(self.TEST_USERNAME in self.RPC_DAEMON.DAEMON. registered_factories['auth'].get_superusers()) rpc_connection = Connection(username=self.TEST_USERNAME, password=self.TEST_PASSWORD) test_auth = rpc_connection.get_connection('auth') self.assertTrue(test_auth.is_superuser()) # Ensure that user can start a test VM and delete it test_vm = self.create_vm('TEST_VM_1', 'Local') self.parse_command('start %s' % test_vm.get_name(), username=self.TEST_USERNAME, password=self.TEST_PASSWORD) self.parse_command('stop %s' % test_vm.get_name(), username=self.TEST_USERNAME, password=self.TEST_PASSWORD) self.parse_command('delete --delete-data %s' % test_vm.get_name(), username=self.TEST_USERNAME, password=self.TEST_PASSWORD) # Delete the user from the superuser group using the argument parser self.parser.parse_arguments( 'permission --delete-superuser %s --global' % self.TEST_USERNAME) # Assert that the user is no longer considered a superuser self.assertFalse(test_auth.is_superuser()) # Assert that the user no longer has access to the superuser permission self.assertFalse(test_auth.is_superuser()) self.assertFalse(self.TEST_USERNAME in self.RPC_DAEMON.DAEMON. registered_factories['auth'].get_superusers())
def authenticate_username_password(self, args, ignore_cluster): """Authenticate using username and password""" # Check if user/password have been passed. Else, ask for them. username = args.username if args.username else System.getUserInput( 'Username: '******'Password: ', password=True ).rstrip() self.rpc = Connection(username=username, password=password, ignore_cluster=ignore_cluster) self.session_id = self.rpc.session_id self.username = self.rpc.username
import sys import os import json from mcvirt.client.rpc import Connection # noqa from mcvirt.constants import DirectoryLocation # noqa # Obtain Drbd resource name from argument drbd_resource = os.environ['DRBD_RESOURCE'] # Determine sync state from arguments sync_state = bool(int(sys.argv[1])) if len(sys.argv) > 1 else False # Ensure that the hook config exists if not os.path.exists(DirectoryLocation.DRBD_HOOK_CONFIG): sys.exit(0) # Read the hook config with open(DirectoryLocation.DRBD_HOOK_CONFIG, 'r') as fh: config = json.load(fh) # Create RPC connection and obtain hard drive factory rpc = Connection(username=config['username'], password=config['password']) hard_drive_factory = rpc.get_connection('hard_drive_factory') # Obtain hard drive object and set sync state hard_drive_object = hard_drive_factory.getDrbdObjectByResourceName( drbd_resource) rpc.annotate_object(hard_drive_object) hard_drive_object.setSyncState(sync_state, update_remote=True)
sys.path.insert(0, '/usr/lib') from mcvirt.client.rpc import Connection # noqa from mcvirt.constants import DirectoryLocation # noqa # Obtain Drbd resource name from argument drbd_resource = os.environ['DRBD_RESOURCE'] # Determine sync state from arguments sync_state = bool(int(sys.argv[1])) if len(sys.argv) > 1 else False # Ensure that the hook config exists if not os.path.exists(DirectoryLocation.DRBD_HOOK_CONFIG): sys.exit(0) # Read the hook config with open(DirectoryLocation.DRBD_HOOK_CONFIG, 'r') as fh: config = json.load(fh) # Create RPC connection and obtain hard drive factory rpc = Connection(username=config['username'], password=config['password']) hard_drive_factory = rpc.get_connection('hard_drive_factory') # Obtain hard drive object and set sync state hard_drive_object = hard_drive_factory.getDrbdObjectByResourceName( drbd_resource ) rpc.annotate_object(hard_drive_object) hard_drive_object.setSyncState(sync_state, update_remote=True)
def add_node(self, node_connection_string): """Connect to a remote MCVirt machine, setup shared authentication and clusters the machines. """ # Ensure the user has privileges to manage the cluster self._get_registered_object('auth').assert_permission( PERMISSIONS.MANAGE_CLUSTER) # Ensure that the IP address configurations has been made correctly self.check_ip_configuration() try: config_json = base64.b64decode(node_connection_string) node_config = json.loads(config_json) assert 'username' in node_config and node_config['username'] assert 'password' in node_config and node_config['password'] assert 'ip_address' in node_config and node_config['ip_address'] assert 'hostname' in node_config and node_config['hostname'] assert 'ca_cert' in node_config and node_config['ca_cert'] except (TypeError, ValueError, AssertionError): raise InvalidConnectionString('Connection string is invalid') # Determine if node is already connected to cluster if self.check_node_exists(node_config['hostname']): raise NodeAlreadyPresent( 'Node %s is already connected to the cluster' % node_config['hostname']) # Create CA public key for machine ssl_object = self._get_registered_object( 'certificate_generator_factory').get_cert_generator( node_config['hostname']) ssl_object.ca_pub_file = node_config['ca_cert'] # Check remote machine, to ensure it can be synced without any # conflicts remote = Connection(username=node_config['username'], password=node_config['password'], host=node_config['hostname']) self.check_remote_machine(remote) remote = None original_cluster_nodes = self.get_nodes() # Add remote node self.add_node_configuration( node_name=node_config['hostname'], ip_address=node_config['ip_address'], connection_user=node_config['username'], connection_password=node_config['password'], ca_key=node_config['ca_cert']) # Obtain node connection to new node remote_node = self.get_remote_node(node_config['hostname']) # Generate local connection user for new remote node local_connection_info = self.generate_connection_info() # Add the local node to the new remote node remote_cluster_instance = remote_node.get_connection('cluster') remote_cluster_instance.add_node_configuration( node_name=local_connection_info[0], ip_address=local_connection_info[1], connection_user=local_connection_info[2], connection_password=local_connection_info[3], ca_key=local_connection_info[4]) new_node_cert_gen_factory = remote_node.get_connection( 'certificate_generator_factory') # Create client certificates for libvirt for the new node to connect to the # current cluster node new_node_cert_gen = new_node_cert_gen_factory.get_cert_generator( get_hostname()) remote_node.annotate_object(new_node_cert_gen) # Generate CSR csr = new_node_cert_gen.generate_csr() # Sign CSR cert_gen_factory = self._get_registered_object( 'certificate_generator_factory') cert_gen = cert_gen_factory.get_cert_generator(node_config['hostname'], remote=True) pub_key = cert_gen.sign_csr(csr) # Add public key to new node new_node_cert_gen.add_public_key(pub_key) # Create client certificate for libvirt for the current cluster node to connect # to the new node cert_gen = cert_gen_factory.get_cert_generator(node_config['hostname']) # Generate CSR csr = cert_gen.generate_csr() # Sign CSR new_node_cert_gen = new_node_cert_gen_factory.get_cert_generator( get_hostname(), remote=True) remote_node.annotate_object(new_node_cert_gen) pub_key = new_node_cert_gen.sign_csr(csr) # Add public key to local node cert_gen.add_public_key(pub_key) # Sync credentials to/from old nodes in the cluster for original_node in original_cluster_nodes: # Share connection information between cluster node and new node original_node_remote = self.get_remote_node(original_node) original_cluster = original_node_remote.get_connection('cluster') original_node_con_info = original_cluster.generate_connection_info( ) remote_cluster_instance.add_node_configuration( node_name=original_node_con_info[0], ip_address=original_node_con_info[1], connection_user=original_node_con_info[2], connection_password=original_node_con_info[3], ca_key=original_node_con_info[4]) new_node_con_info = remote_cluster_instance.generate_connection_info( ) original_cluster.add_node_configuration( node_name=new_node_con_info[0], ip_address=new_node_con_info[1], connection_user=new_node_con_info[2], connection_password=new_node_con_info[3], ca_key=new_node_con_info[4]) # Create client certificates for libvirt for the new node to connect to the # current cluster node new_node_cert_gen = new_node_cert_gen_factory.get_cert_generator( original_node) remote_node.annotate_object(new_node_cert_gen) csr = new_node_cert_gen.generate_csr() original_node_cert_gen_factory = original_node_remote.get_connection( 'certificate_generator_factory') original_node_cert_gen = original_node_cert_gen_factory.get_cert_generator( node_config['hostname'], remote=True) original_node_remote.annotate_object(original_node_cert_gen) pub_key = original_node_cert_gen.sign_csr(csr) new_node_cert_gen.add_public_key(pub_key) # Create client certificate for libvirt for the current cluster node to connect # to the new node original_node_cert_gen = original_node_cert_gen_factory.get_cert_generator( node_config['hostname']) original_node_remote.annotate_object(original_node_cert_gen) # Generate CSR csr = original_node_cert_gen.generate_csr() # Sign CSR new_node_cert_gen = new_node_cert_gen_factory.get_cert_generator( original_node, remote=True) remote_node.annotate_object(new_node_cert_gen) pub_key = new_node_cert_gen.sign_csr(csr) # Add public key to original node original_node_cert_gen.add_public_key(pub_key) # If Drbd is enabled on the local node, configure/enable it on the remote node if self._get_registered_object('node_drbd').is_enabled(): remote_drbd = remote_node.get_connection('node_drbd') remote_drbd.enable( secret=MCVirtConfig().get_config()['drbd']['secret']) # Sync users self.sync_users(remote_node) # Sync networks self.sync_networks(remote_node) # Sync global permissions self.sync_permissions(remote_node) # Sync VMs self.sync_virtual_machines(remote_node)
class TestBase(unittest.TestCase): """Provide base test case, with constructor/destructor for providing access to the parser and RPC """ # Define RPC credentials, which are the default superuser credentials # that are supplied with MCVirt RPC_USERNAME = '******' RPC_PASSWORD = '******' def setUp(self): """Obtain connections to the daemon and create various member variables. """ # Create and store RPC connection to daemon. self.rpc = Connection(self.RPC_USERNAME, self.RPC_PASSWORD) # Create and store parser instance self.parser = Parser(verbose=False) # Obtain the session ID from the RPC connection and re-use this, # so that the parser does not need to authenticate with a password # self.parser.parse_arguments('list --username %s --password %s' % (self.RPC_USERNAME, # self.RPC_PASSWORD)) self.parser.USERNAME = self.RPC_USERNAME self.parser.SESSION_ID = self.rpc.session_id # Setup variable for test VM self.test_vms = \ { 'TEST_VM_1': { 'name': 'mcvirt-unittest-vm', 'cpu_count': 1, 'memory_allocation': 100, 'disk_size': [100], 'networks': ['Production'] }, 'TEST_VM_2': { 'name': 'mcvirt-unittest-vm2', 'cpu_count': 2, 'memory_allocation': 120, 'disk_size': [100], 'networks': ['Production'] } } # Ensure any test VM is stopped and removed from the machine self.stop_and_delete(self.test_vms['TEST_VM_2']['name']) self.stop_and_delete(self.test_vms['TEST_VM_1']['name']) self.vm_factory = self.rpc.get_connection('virtual_machine_factory') self.test_network_name = 'testnetwork' self.test_physical_interface = 'vmbr0' self.network_factory = self.rpc.get_connection('network_factory') # Determine if the test network exists. If so, delete it if self.network_factory.check_exists(self.test_network_name): network = self.network_factory.get_network_by_name( self.test_network_name) self.rpc.annotate_object(network) network.delete() def tearDown(self): """Destroy stored objects.""" # Ensure any test VM is stopped and removed from the machine self.rpc.ignore_drbd() self.stop_and_delete(self.test_vms['TEST_VM_2']['name']) self.stop_and_delete(self.test_vms['TEST_VM_1']['name']) # Remove the test network, if it exists if self.network_factory.check_exists(self.test_network_name): network = self.network_factory.get_network_by_name( self.test_network_name) self.rpc.annotate_object(network) network.delete() self.network_factory = None self.vm_factory = None self.rpc = None self.parser = None def create_vm(self, vm_name, storage_type): """Create a test VM, annotate object and ensure it exists""" vm_object = self.vm_factory.create( self.test_vms[vm_name]['name'], self.test_vms[vm_name]['cpu_count'], self.test_vms[vm_name]['memory_allocation'], self.test_vms[vm_name]['disk_size'], self.test_vms[vm_name]['networks'], storage_type=storage_type) self.rpc.annotate_object(vm_object) self.assertTrue( self.vm_factory.check_exists(self.test_vms[vm_name]['name'])) return vm_object def stop_and_delete(self, vm_name): """Stop and remove a virtual machine""" virtual_machine_factory = self.rpc.get_connection( 'virtual_machine_factory') if virtual_machine_factory.check_exists(vm_name): vm_object = virtual_machine_factory.getVirtualMachineByName( vm_name) self.rpc.annotate_object(vm_object) # Reset sync state for any Drbd disks for disk_object in vm_object.getHardDriveObjects(): self.rpc.annotate_object(disk_object) if disk_object.get_type() == 'Drbd': disk_object.setSyncState(True) if not vm_object.isRegistered(): # Manually register VM on local node vm_object.register() # Stop the VM if it is running if vm_object.getPowerState() == PowerStates.RUNNING.value: vm_object.stop() if vm_object.getLockState() is LockStates.LOCKED.value: vm_object.setLockState(LockStates.UNLOCKED.value) # Delete VM vm_object.delete(True)
class Parser(object): """Provides an argument parser for MCVirt.""" AUTH_FILE = '.mcvirt-auth' def __init__(self, verbose=True): """Configure the argument parser object.""" self.print_output = [] self.username = None self.session_id = None self.rpc = None self.auth_cache_file = os.getenv('HOME') + '/' + self.AUTH_FILE self.verbose = verbose self.parent_parser = ThrowingArgumentParser(add_help=False) self.global_option = self.parent_parser.add_argument_group('Global optional arguments') self.global_option.add_argument('--username', '-U', dest='username', help='MCVirt username') self.global_option.add_argument('--password', dest='password', help='MCVirt password') self.global_option.add_argument('--cache-credentials', dest='cache_credentials', action='store_true', help=('Store the session ID, so it can be used for ' 'multiple MCVirt calls.')) self.global_option.add_argument('--ignore-failed-nodes', dest='ignore_failed_nodes', help='Ignores nodes that are inaccessible', action='store_true') self.global_option.add_argument('--accept-failed-nodes-warning', dest='accept_failed_nodes_warning', help=argparse.SUPPRESS, action='store_true') self.global_option.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 StartParser(self.subparsers, self.parent_parser) # Add arguments for stopping a VM StopParser(self.subparsers, self.parent_parser) # Add arguments for resetting a VM ResetParser(self.subparsers, self.parent_parser) # Add arguments for shutting down a VM ShutdownParser(self.subparsers, self.parent_parser) # Add arguments for fixing deadlock on a vm ClearMethodLockParser(self.subparsers, self.parent_parser) # Add arguments for ISO functions IsoParser(self.subparsers, self.parent_parser) # Add arguments for managing users UserParser(self.subparsers, self.parent_parser) # Add arguments for creating a VM CreateParser(self.subparsers, self.parent_parser) # Get arguments for deleting a VM DeleteParser(self.subparsers, self.parent_parser) RegisterParser(self.subparsers, self.parent_parser) UnregisterParser(self.subparsers, self.parent_parser) # Get arguments for updating a VM UpdateParser(self.subparsers, self.parent_parser) PermissionParser(self.subparsers, self.parent_parser) GroupParser(self.subparsers, self.parent_parser) # Create subparser for network-related commands NetworkParser(self.subparsers, self.parent_parser) # Get arguments for getting VM information InfoParser(self.subparsers, self.parent_parser) # Get arguments for listing VMs ListParser(self.subparsers, self.parent_parser) # Get arguments for cloning a VM CloneParser(self.subparsers, self.parent_parser) # Get arguments for cloning a VM DuplicateParser(self.subparsers, self.parent_parser) # Get arguments for migrating a VM MigrateParser(self.subparsers, self.parent_parser) # Create sub-parser for moving VMs MoveParser(self.subparsers, self.parent_parser) # Create sub-parser for cluster-related commands ClusterParser(self.subparsers, self.parent_parser) StorageParser(self.subparsers, self.parent_parser) HardDriveParser(self.subparsers, self.parent_parser) # Create subparser for commands relating to the local node configuration NodeParser(self.subparsers, self.parent_parser) # Create sub-parser for VM verification VerifyParser(self.subparsers, self.parent_parser) # Create sub-parser for VM Disk resync ResyncParser(self.subparsers, self.parent_parser) # Create sub-parser for Drbd-related commands DrbdParser(self.subparsers, self.parent_parser) # Create sub-parser for watchdog WatchdogParser(self.subparsers, self.parent_parser) # Create sub-parser for backup commands BackupParser(self.subparsers, self.parent_parser) # Create sub-parser for managing VM locks LockParser(self.subparsers, self.parent_parser) self.exit_parser = self.subparsers.add_parser('exit', help='Exits the MCVirt shell', parents=[self.parent_parser]) def print_status(self, status): """Print if the user has specified that the parser should print statuses.""" if self.verbose: print status else: self.print_output.append(status) def check_ignore_failed(self, args): """Check ignore failed""" 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 return True return False def authenticate_saved_session(self, ignore_cluster): """Attempt to authenticate using saved session""" # Try logging in with saved session auth_session = None try: with open(self.auth_cache_file, 'r') as cache_fh: auth_username = cache_fh.readline().strip() auth_session = cache_fh.readline().strip() except IOError: pass if auth_session: try: self.rpc = Connection(username=auth_username, session_id=auth_session, ignore_cluster=ignore_cluster) self.session_id = self.rpc.session_id self.username = self.rpc.username except AuthenticationError: # If authentication fails with cached session, # print error, attempt to remove sessionn file and # remove rpc connection self.print_status('Authentication error occured when using saved session.') try: os.remove(self.auth_cache_file) except OSError: pass self.rpc = None def authenticate_username_password(self, args, ignore_cluster): """Authenticate using username and password""" # Check if user/password have been passed. Else, ask for them. username = args.username if args.username else System.getUserInput( 'Username: '******'Password: '******'w') as cache_fh: cache_fh.write("%s\n%s" % (self.rpc.username, self.rpc.session_id)) except OSError: pass 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) ignore_cluster = self.check_ignore_failed(args) if self.session_id and self.username: self.rpc = Connection(username=self.username, session_id=self.session_id, ignore_cluster=ignore_cluster) else: # Obtain connection to Pyro server if not (args.password or args.username): self.authenticate_saved_session(ignore_cluster) if not self.rpc: self.authenticate_username_password(args, ignore_cluster) self.store_cached_session(args) if args.ignore_drbd: self.rpc.ignore_drbd() # If a custom parser function has been defined, used this and exit # instead of running through (old) main parser workflow if 'func' in dir(args): args.func(args=args, p_=self) else: raise ArgumentParserException('No handler registered for parser')