예제 #1
0
    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)
예제 #2
0
    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
예제 #3
0
    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
예제 #4
0
    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
예제 #5
0
    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
예제 #6
0
    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.')
예제 #7
0
    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
예제 #8
0
    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))
예제 #9
0
 def cli():
     """Print an warning message"""
     miqcli_log.warning(MESSAGE)