def invoke(self, ctx): """Invoke the sub-command selected. This is where things start to get real. We load configuration settings based on the order preference, update the click context with the final configuration settings, connect to the ManageIQ server and then invoke the command. When the help parameter is given for any sub-command, we do not attempt connection to ManageIQ server. Only show params and exit. :param ctx: Click context. :type ctx: Namespace """ # first lets make sure the sub-command given is valid if ctx.protected_args[0] not in self.list_commands(ctx): _abort_invalid_commands(ctx, ctx.protected_args[0]) if '--help' not in ctx.args: # get parent context parent_ctx = click.get_current_context().find_root() # create config object config = Config(verbose=parent_ctx.params['verbose']) # load config settings in the following order: # 1. Default configuration settings # - managed by ManageIQ CLI constants # 2. CLI parameters # - $ miqcli --options # 3. YAML configuration @ /etc/miqcli/miqcli.[yml|yaml] # 4. YAML configuration @ ./miqcli.[yml|yaml] # 5. Environment variable # - $ export MIQ_CFG="{'key': 'val'}" config.from_yml(CFG_DIR, CFG_NAME) config.from_yml(os.path.join(os.getcwd()), CFG_NAME) config.from_env('MIQ_CFG') # set the final parameters after loading config settings click.get_current_context().find_root().params.update( dict(config) ) # notify user if default config is used if is_default_config_used(): log.warning('Default configuration is used.') # create the client api object client = ClientAPI(click.get_current_context().find_root().params) # connect to manageiq server client.connect() # save the client api pointer reference in the parent context for # each collection to access setattr(parent_ctx, 'client_api', client) del parent_ctx super(SubCollections, self).invoke(ctx)
def status(self, req_id): """Print the status for a automation request. :: Handles getting information for an existing automation request and displaying/returning back to the user. :param req_id: id of the automation request :type req_id: str :return: automation request object or list of automation request objects """ status = OrderedDict() query = BasicQuery(self.collection) if req_id: automation_requests = query(("id", "=", req_id)) if len(automation_requests) < 1: log.warning('Automation request id: %s not found!' % req_id) return req = automation_requests[0] status['state'] = req.request_state status['status'] = req.status status['message'] = req.message log.info('-' * 50) log.info('Automation request'.center(50)) log.info('-' * 50) log.info(' * ID: %s' % req_id) for key, value in status.items(): log.info(' * %s: %s' % (key.upper(), value)) # if verbosity is set, get more info about the request log.debug('\n' + pformat(req.options, indent=4)) log.info('-' * 50) return req else: automation_requests = query(("request_state", "!=", "finished")) if len(automation_requests) < 1: log.warning('No active automation requests at this time.') return None log.info('-' * 50) log.info(' Active automation requests'.center(50)) log.info('-' * 50) for item in automation_requests: log.info( ' * ID: %s\tINSTANCE: %s\t STATE: %s\t STATUS: %s' % (item.id, item.options, item.request_state, item.status)) log.info('-' * 50) return automation_requests
def __call__(self, query, attr=None): """Performs a advanced query on a collection. :param query: multiple queries containing name, operand and value :type query: list :return: collection resources matching the supplied query :rtype: list Usage: .. code-block: python query = AdvancedQuery(vm_collection) query([('name', '=', 'vm_foo'), '&', ('id', '>', '9999934')]) # -- or -- query.__call__([('name', '=', 'vm_foo'), '&', ('id', '>', '9999934')]) """ adv_query = '' if len(query) % 2 == 0: log.warning('Query attempted is invalid: {0}'.format(query)) return self.resources # build query in string form while query: _query = query.pop(0) if isinstance(_query, tuple) and len(_query) != 3: log.warning('Query must contain three indexes (name, operator,' ' value)') return self.resources elif isinstance(_query, tuple): adv_query += str("Q('" + str(_query[0]) + "', '" + str(_query[1])) + "', '" + str( _query[2]) + "')" elif isinstance(_query, str): adv_query += ' {0} '.format(_query) try: resources = getattr(self.collection, 'filter')(eval(adv_query)) self.resources = resources.resources if attr: for ent in resources.resources: ent.reload(True, True, attr) except (APIException, ValueError, TypeError) as e: # most likely user passed an invalid attribute name log.error('Query attempted failed: {0}, error: {1}'.format( query, e)) return self.resources
def status(self, req_id): """Print the status for a provision request. :: Handles getting information for an existing provision request and displaying/returning back to the user. :param req_id: id of the provisioning request :type req_id: str :return: provision request object or list of provision request objects """ status = OrderedDict() query = BasicQuery(self.collection) if req_id: provision_requests = query(("id", "=", req_id)) if len(provision_requests) < 1: log.warning('Provision request id: %s not found!' % req_id) return None req = provision_requests[0] status['state'] = req.request_state status['status'] = req.status status['message'] = req.message log.info('-' * 50) log.info('Provision request'.center(50)) log.info('-' * 50) log.info(' * ID: %s' % req_id) log.info(' * VM: %s' % req.options['vm_name']) for key, value in status.items(): log.info(' * %s: %s' % (key.upper(), value)) log.info('-' * 50) return req else: provision_requests = query(("request_state", "!=", "finished")) if len(provision_requests) < 1: log.warning(' * No active provision requests at this time') return None log.info('-' * 50) log.info(' Active provision requests'.center(50)) log.info('-' * 50) for item in provision_requests: log.info(' * ID: %s\tINSTANCE: %s\tSTATE: %s\tSTATUS: %s' % (item.id, item.options['vm_name'], item.request_state, item.status)) log.info('-' * 50) return provision_requests
def status(self, req_id): """Get the status for a request task. :: Handles getting information for an existing request and displaying/returning back to the user. :param req_id: id of the request :type req_id: str :return: request task object or list of request objects """ status = OrderedDict() query = BasicQuery(self.collection) if req_id: requests_tasks = query(("id", "=", req_id)) if len(requests_tasks) < 1: log.warning('Request id: %s not found!' % req_id) return None req = requests_tasks[0] status['state'] = req.state status['status'] = req.status status['message'] = req.message log.info('-' * 50) log.info('Request'.center(50)) log.info('-' * 50) log.info(' * ID: %s' % req_id) log.info(' * Description: %s' % req['description']) for key, value in status.items(): log.info(' * %s: %s' % (key.upper(), value)) log.info('-' * 50) return req else: requests_tasks = query(("state", "!=", "finished")) if len(requests_tasks) < 1: log.warning(' * No active requests tasks at this time') return None log.info('-' * 50) log.info(' Active requests'.center(50)) log.info('-' * 50) for item in requests_tasks: log.info(' * ID: %s\tDESCRIPTION: %s\tSTATE: %s\tSTATUS: %s' % (item.id, item.description, item.state, item.status)) log.info('-' * 50) return requests_tasks
def from_env(self, var): """Load configuration settings from environment variable. :param var: variable name in dict syntax :type var: str """ try: for key, value in ast.literal_eval(os.environ[var]).items(): self[key] = value except KeyError: if self._verbose: log.warning('Config environment variable is undefined.') except SyntaxError: log.abort('The syntax of the environment variable content ' 'is not valid. Check its content.')
def __call__(self, query, attr=None): """Performs a basic query on a collection. :param query: query containing name, operand and value :type query: tuple :return: collection resources matching the supplied query :rtype: list Usage: .. code-block: python # query vms collection to find the following vm by name query = BasicQuery(vm_collection) query(('name', '=', 'vm_foo')) # -- or -- query.__call__(('name', '=', 'vm_foo')) """ if len(query) != 3: log.warning('Query must contain three indexes. i.e. ' '(name, operand, value)') return self.resources try: resources = getattr(self.collection, 'filter')(Q(query[0], query[1], query[2])) self.resources = resources.resources if attr: for ent in resources.resources: ent.reload(True, True, attr) except (APIException, ValueError) as e: log.error('Query attempted failed: {0}, error: {1}'.format( query, e)) return self.resources
def from_yml(self, directory, filename): """Load configuration settings from yml file. :param directory: directory to scan for config file :type directory: str :param filename: config filename :type filename: str """ _cfg_file = None # verify directory is defined if not os.path.isdir(directory): if self._verbose: log.warning('Directory {0} is undefined.'.format(directory)) return # verify config file exists for entry in os.listdir(directory): _file = os.path.splitext(entry) if _file[0] == filename and _file[1] in CFG_FILE_EXT: _cfg_file = os.path.join(directory, entry) break if _cfg_file is None and self._verbose: log.warning('Config file at {0} is undefined.'.format(directory)) return if _cfg_file is None: return # load config try: with open(_cfg_file, mode='rb') as fp: config_data = yaml.load(fp) if isinstance(config_data, str): log.abort('Config file {0} formatted incorrectly.'.format( _cfg_file)) elif config_data is None: log.warning('Config file {0} is empty.'.format(_cfg_file)) else: for key, value in config_data.items(): self[key] = value except yaml.YAMLError as e: if self._verbose: log.debug('Standard error: {0}'.format(e)) log.abort('Error in config {0}.'.format(_cfg_file))
def cli(): """Print an warning message""" miqcli_log.warning(MESSAGE)