Exemplo n.º 1
0
 def _test_it():
     with task_manager.TaskManager(self.context, 'node-id') as task:
         task.spawn_after(spawn_mock, 1, 2, foo='bar', cat='meow')
         task.release_resources = task_release_mock
         raise exception.IronicException('foo')
Exemplo n.º 2
0
    def _command(self, node, method, params, wait=False):
        """Sends command to agent.

        :param node: A Node object.
        :param method: A string represents the command to be executed by
                       agent.
        :param params: A dictionary containing params used to form the request
                       body.
        :param wait: True to wait for the command to finish executing, False
                     otherwise.
        :raises: IronicException when failed to issue the request or there was
                 a malformed response from the agent.
        :raises: AgentAPIError when agent failed to execute specified command.
        :returns: A dict containing command result from agent, see
                  get_commands_status for a sample.
        """
        url = self._get_command_url(node)
        body = self._get_command_body(method, params)
        request_params = {'wait': str(wait).lower()}
        agent_token = node.driver_internal_info.get('agent_secret_token')
        if agent_token:
            request_params['agent_token'] = agent_token
        LOG.debug('Executing agent command %(method)s for node %(node)s', {
            'node': node.uuid,
            'method': method
        })

        try:
            response = self.session.post(url,
                                         params=request_params,
                                         data=body,
                                         timeout=CONF.agent.command_timeout)
        except (requests.ConnectionError, requests.Timeout) as e:
            msg = (_('Failed to connect to the agent running on node %(node)s '
                     'for invoking command %(method)s. Error: %(error)s') % {
                         'node': node.uuid,
                         'method': method,
                         'error': e
                     })
            LOG.error(msg)
            raise exception.AgentConnectionFailed(reason=msg)
        except requests.RequestException as e:
            msg = (_('Error invoking agent command %(method)s for node '
                     '%(node)s. Error: %(error)s') % {
                         'method': method,
                         'node': node.uuid,
                         'error': e
                     })
            LOG.error(msg)
            raise exception.IronicException(msg)

        # TODO(russellhaering): real error handling
        try:
            result = response.json()
        except ValueError:
            msg = _('Unable to decode response as JSON.\n'
                    'Request URL: %(url)s\nRequest body: "%(body)s"\n'
                    'Response status code: %(code)s\n'
                    'Response: "%(response)s"') % ({
                        'response': response.text,
                        'body': body,
                        'url': url,
                        'code': response.status_code
                    })
            LOG.error(msg)
            raise exception.IronicException(msg)

        LOG.debug(
            'Agent command %(method)s for node %(node)s returned '
            'result %(res)s, error %(error)s, HTTP status code %(code)d', {
                'node': node.uuid,
                'method': method,
                'res': result.get('command_result'),
                'error': result.get('command_error'),
                'code': response.status_code
            })

        if response.status_code >= http_client.BAD_REQUEST:
            LOG.error(
                'Agent command %(method)s for node %(node)s failed. '
                'Expected 2xx HTTP status code, got %(code)d.', {
                    'method': method,
                    'node': node.uuid,
                    'code': response.status_code
                })
            raise exception.AgentAPIError(node=node.uuid,
                                          status=response.status_code,
                                          error=result.get('faultstring'))

        return result
Exemplo n.º 3
0
 def test_do_next_deploy_step_execute_ironic_exception(self):
     self._do_next_deploy_step_execute_fail(
         exception.IronicException('foo'), False)
Exemplo n.º 4
0
 def ironicexception(self):
     raise exception.IronicException("Fake!")
Exemplo n.º 5
0
 def test_collect_ramdisk_logs_storage_command_fail(
         self, mock_collect, mock_store):
     mock_collect.side_effect = exception.IronicException('boom')
     self.assertIsNone(driver_utils.collect_ramdisk_logs(self.node))
     self.assertFalse(mock_store.called)
Exemplo n.º 6
0
 def fail(self, context, message):
     assert isinstance(context, ir_ctx.RequestContext)
     raise exception.IronicException(message)
Exemplo n.º 7
0
def execute(*cmd, **kwargs):
    """Helper method to execute command with optional retry.

    If you add a run_as_root=True command, don't forget to add the
    corresponding filter to etc/nova/rootwrap.d !

    :param cmd:                Passed to subprocess.Popen.
    :param process_input:      Send to opened process.
    :param check_exit_code:    Single bool, int, or list of allowed exit
                               codes.  Defaults to [0].  Raise
                               exception.ProcessExecutionError unless
                               program exits with one of these code.
    :param delay_on_retry:     True | False. Defaults to True. If set to
                               True, wait a short amount of time
                               before retrying.
    :param attempts:           How many times to retry cmd.
    :param run_as_root:        True | False. Defaults to False. If set to True,
                               the command is run with rootwrap.

    :raises exception.IronicException: on receiving unknown arguments
    :raises exception.ProcessExecutionError:

    :returns: a tuple, (stdout, stderr) from the spawned process, or None if
             the command fails.
    """
    process_input = kwargs.pop('process_input', None)
    check_exit_code = kwargs.pop('check_exit_code', [0])
    ignore_exit_code = False
    if isinstance(check_exit_code, bool):
        ignore_exit_code = not check_exit_code
        check_exit_code = [0]
    elif isinstance(check_exit_code, int):
        check_exit_code = [check_exit_code]
    delay_on_retry = kwargs.pop('delay_on_retry', True)
    attempts = kwargs.pop('attempts', 1)
    run_as_root = kwargs.pop('run_as_root', False)
    shell = kwargs.pop('shell', False)

    if len(kwargs):
        raise exception.IronicException(
            _('Got unknown keyword args '
              'to utils.execute: %r') % kwargs)

    if run_as_root and os.geteuid() != 0:
        cmd = ['sudo', 'nova-rootwrap', CONF.rootwrap_config] + list(cmd)

    cmd = map(str, cmd)

    while attempts > 0:
        attempts -= 1
        try:
            LOG.debug(_('Running cmd (subprocess): %s'), ' '.join(cmd))
            _PIPE = subprocess.PIPE  # pylint: disable=E1101

            if os.name == 'nt':
                preexec_fn = None
                close_fds = False
            else:
                preexec_fn = _subprocess_setup
                close_fds = True

            obj = subprocess.Popen(cmd,
                                   stdin=_PIPE,
                                   stdout=_PIPE,
                                   stderr=_PIPE,
                                   close_fds=close_fds,
                                   preexec_fn=preexec_fn,
                                   shell=shell)
            result = None
            if process_input is not None:
                result = obj.communicate(process_input)
            else:
                result = obj.communicate()
            obj.stdin.close()  # pylint: disable=E1101
            _returncode = obj.returncode  # pylint: disable=E1101
            LOG.debug(_('Result was %s') % _returncode)
            if not ignore_exit_code and _returncode not in check_exit_code:
                (stdout, stderr) = result
                raise exception.ProcessExecutionError(exit_code=_returncode,
                                                      stdout=stdout,
                                                      stderr=stderr,
                                                      cmd=' '.join(cmd))
            return result
        except exception.ProcessExecutionError:
            if not attempts:
                raise
            else:
                LOG.debug(_('%r failed. Retrying.'), cmd)
                if delay_on_retry:
                    greenthread.sleep(random.randint(20, 200) / 100.0)
        finally:
            # NOTE(termie): this appears to be necessary to let the subprocess
            #               call clean something up in between calls, without
            #               it two execute calls in a row hangs the second one
            greenthread.sleep(0)
Exemplo n.º 8
0
    def _command(self,
                 node,
                 method,
                 params,
                 wait=False,
                 command_timeout_factor=1):
        """Sends command to agent.

        :param node: A Node object.
        :param method: A string represents the command to be executed by
                       agent.
        :param params: A dictionary containing params used to form the request
                       body.
        :param wait: True to wait for the command to finish executing, False
                     otherwise.
        :param command_timeout_factor: An integer, default 1, by which to
                                       multiply the [agent]command_timeout
                                       value. This is intended for use with
                                       extremely long running commands to
                                       the agent ramdisk where a general
                                       timeout value should not be extended
                                       in all cases.
        :raises: IronicException when failed to issue the request or there was
                 a malformed response from the agent.
        :raises: AgentAPIError when agent failed to execute specified command.
        :returns: A dict containing command result from agent, see
                  get_commands_status for a sample.
        """
        url = self._get_command_url(node)
        body = self._get_command_body(method, params)
        request_params = {'wait': str(wait).lower()}
        agent_token = node.driver_internal_info.get('agent_secret_token')
        if agent_token:
            request_params['agent_token'] = agent_token
        LOG.debug('Executing agent command %(method)s for node %(node)s', {
            'node': node.uuid,
            'method': method
        })

        try:
            response = self.session.post(url,
                                         params=request_params,
                                         data=body,
                                         timeout=CONF.agent.command_timeout *
                                         command_timeout_factor)
        except (requests.ConnectionError, requests.Timeout) as e:
            msg = (_('Failed to connect to the agent running on node %(node)s '
                     'for invoking command %(method)s. Error: %(error)s') % {
                         'node': node.uuid,
                         'method': method,
                         'error': e
                     })
            LOG.error(msg)
            raise exception.AgentConnectionFailed(reason=msg)
        except requests.RequestException as e:
            msg = (_('Error invoking agent command %(method)s for node '
                     '%(node)s. Error: %(error)s') % {
                         'method': method,
                         'node': node.uuid,
                         'error': e
                     })
            LOG.error(msg)
            raise exception.IronicException(msg)

        # TODO(russellhaering): real error handling
        try:
            result = response.json()
        except ValueError:
            msg = _('Unable to decode response as JSON.\n'
                    'Request URL: %(url)s\nRequest body: "%(body)s"\n'
                    'Response status code: %(code)s\n'
                    'Response: "%(response)s"') % ({
                        'response': response.text,
                        'body': body,
                        'url': url,
                        'code': response.status_code
                    })
            LOG.error(msg)
            raise exception.IronicException(msg)

        error = result.get('command_error')
        exc_type = None
        if error:
            # if an error, we should see if a type field exists. This type
            # field may signal an exception that is compatability based.
            exc_type = error.get('type')

        LOG.debug(
            'Agent command %(method)s for node %(node)s returned '
            'result %(res)s, error %(error)s, HTTP status code %(code)d', {
                'node': node.uuid,
                'method': method,
                'res': result.get('command_result'),
                'error': error,
                'code': response.status_code
            })

        if response.status_code >= http_client.BAD_REQUEST:
            LOG.error(
                'Agent command %(method)s for node %(node)s failed. '
                'Expected 2xx HTTP status code, got %(code)d.', {
                    'method': method,
                    'node': node.uuid,
                    'code': response.status_code
                })
            raise exception.AgentAPIError(node=node.uuid,
                                          status=response.status_code,
                                          error=result.get('faultstring'))
        if exc_type == 'TypeError':
            LOG.error(
                'Agent command %(method)s for node %(node)s failed. '
                'Internal %(exc_type)s error detected: Error %(error)s', {
                    'method': method,
                    'node': node.uuid,
                    'exc_type': exc_type,
                    'error': error
                })
            raise exception.AgentAPIError(node=node.uuid,
                                          status=error.get('code'),
                                          error=result.get('faultstring'))

        return result
Exemplo n.º 9
0
    def _command(self, node, method, params, wait=False, poll=False):
        """Sends command to agent.

        :param node: A Node object.
        :param method: A string represents the command to be executed by
                       agent.
        :param params: A dictionary containing params used to form the request
                       body.
        :param wait: True to wait for the command to finish executing, False
                     otherwise.
        :param poll: Whether to poll the command until completion. Provides
                     a better alternative to `wait` for long-running commands.
        :raises: IronicException when failed to issue the request or there was
                 a malformed response from the agent.
        :raises: AgentAPIError when agent failed to execute specified command.
        :raises: AgentInProgress when the command fails to execute as the agent
                 is presently executing the prior command.
        :returns: A dict containing command result from agent, see
                  get_commands_status for a sample.
        """
        assert not (wait and poll)

        url = self._get_command_url(node)
        body = self._get_command_body(method, params)
        request_params = {'wait': str(wait).lower()}
        agent_token = node.driver_internal_info.get('agent_secret_token')
        if agent_token:
            request_params['agent_token'] = agent_token
        LOG.debug('Executing agent command %(method)s for node %(node)s', {
            'node': node.uuid,
            'method': method
        })

        try:
            response = self.session.post(url,
                                         params=request_params,
                                         data=body,
                                         verify=self._get_verify(node),
                                         timeout=CONF.agent.command_timeout)
        except (requests.ConnectionError, requests.Timeout) as e:
            msg = (_('Failed to connect to the agent running on node %(node)s '
                     'for invoking command %(method)s. Error: %(error)s') % {
                         'node': node.uuid,
                         'method': method,
                         'error': e
                     })
            LOG.error(msg)
            raise exception.AgentConnectionFailed(reason=msg)
        except requests.RequestException as e:
            msg = (_('Error invoking agent command %(method)s for node '
                     '%(node)s. Error: %(error)s') % {
                         'method': method,
                         'node': node.uuid,
                         'error': e
                     })
            LOG.error(msg)
            raise exception.IronicException(msg)

        # TODO(russellhaering): real error handling
        try:
            result = response.json()
        except ValueError:
            msg = _('Unable to decode response as JSON.\n'
                    'Request URL: %(url)s\nRequest body: "%(body)s"\n'
                    'Response status code: %(code)s\n'
                    'Response: "%(response)s"') % ({
                        'response': response.text,
                        'body': body,
                        'url': url,
                        'code': response.status_code
                    })
            LOG.error(msg)
            raise exception.IronicException(msg)

        error = result.get('command_error')
        LOG.debug(
            'Agent command %(method)s for node %(node)s returned '
            'result %(res)s, error %(error)s, HTTP status code %(code)d', {
                'node': node.uuid,
                'method': method,
                'res': result.get('command_result'),
                'error': error,
                'code': response.status_code
            })
        if response.status_code >= http_client.BAD_REQUEST:
            faultstring = result.get('faultstring')
            if 'agent_token' in faultstring:
                LOG.error(
                    'Agent command %(method)s for node %(node)s '
                    'failed. Expected 2xx HTTP status code, got '
                    '%(code)d. Error suggests an older ramdisk '
                    'which does not support ``agent_token``. '
                    'This is a fatal error.', {
                        'method': method,
                        'node': node.uuid,
                        'code': response.status_code
                    })
            else:
                LOG.error(
                    'Agent command %(method)s for node %(node)s failed. '
                    'Expected 2xx HTTP status code, got %(code)d.', {
                        'method': method,
                        'node': node.uuid,
                        'code': response.status_code
                    })
            if (response.status_code == http_client.CONFLICT
                    or 'agent is busy' in faultstring.lower()):
                # HTTP 409 check as an explicit check of if the agent
                # is already busy.
                # NOTE(TheJulia): The agent sends upper case A as of
                # late victoria, but lower case the entire message
                # for compatability with pre-late victoria agents
                # which returns HTTP 409.
                raise exception.AgentInProgress(node=node.uuid,
                                                command=method,
                                                error=faultstring)
            raise exception.AgentAPIError(node=node.uuid,
                                          status=response.status_code,
                                          error=faultstring)

        self._raise_if_typeerror(result, node, method)

        if poll:
            result = self._wait_for_command(node, method)

        return result
Exemplo n.º 10
0
 def _lock_again(u):
     with task_manager.acquire(u):
         raise exception.IronicException("Acquired lock twice.")
Exemplo n.º 11
0
 def test___str__non_string(self):
     exc = exception.IronicException(42)
     self.assertEqual("42", exc.__str__())
     self.assertEqual(u"42", exc.__unicode__())