Exemple #1
0
    def __init__(self, conf: K2hr3Conf) -> None:
        """Initializes attributes.

        :param conf: K2hr3Conf object.
        :type K2hr3Conf: K2hr3Conf
        :raises K2hr3UserAgentError: api_url validation error.
        """
        # api_url validated for myself.
        if isinstance(conf, K2hr3Conf) is False:
            raise _K2hr3UserAgentError(
                'conf is a K2hr3Conf instance, not {}'.format(type(conf)))
        try:
            _K2hr3UserAgent.validate_url(conf.k2hr3.api_url)
        except _K2hr3UserAgentError as error:
            raise _K2hr3UserAgentError(
                'a valid url is expected, not {}'.format(
                    conf.k2hr3.api_url)) from error
        self._conf = conf
        self._url = conf.k2hr3.api_url
        # other params validated in oslo_config.
        self._retries = conf.k2hr3.max_retries
        self._allow_self_signed_cert = conf.k2hr3.allow_self_signed_cert
        # init the others.
        self._ips = []  # type: List[str]
        self._instance_id = ''
        self._method = 'DELETE'
        self._params = {'extra': 'openstack-auto-v1'}
        self._headers = {
            'User-Agent':
            'Python-k2hr3_ua/{}.{}'.format(sys.version_info[0],
                                           sys.version_info[1])
        }
        self._response = _K2hr3HttpResponse()
        LOG.debug('useragent initialized.')
Exemple #2
0
    def test_notification_endpoint_info_requeue_test_on_exception(self):
        """Checks if info works correctly.

        NotificationEndpoint::__call_r3api returns REQUEUE in this case.

        NotificationEndpoint::info()
        --> NotificationEndpoint::__call_r3api()
        --> _K2hr3UserAgent::send()                # we mock this method.
        """
        # _K2hr3UserAgent::send() is expected to raise _K2hr3UserAgentError.
        _K2hr3UserAgent.send = MagicMock(
            side_effect=_K2hr3UserAgentError('send error'))

        conf = K2hr3Conf(conf_file_path)
        conf.k2hr3.requeue_on_error = True  # overwrites it True.
        endpoint = K2hr3NotificationEndpoint(conf)
        json_file_path = Path(
            os.sep.join(
                [here, '..', 'tools', 'data',
                 'notifications_neutron.json'])).resolve()
        with json_file_path.open() as fp:
            data = json.load(fp)
            result = endpoint.info(data['ctxt'], data['publisher_id'],
                                   data['event_type'], data['payload'],
                                   data['metadata'])
        # Ensure the__call_r3api is not called.
        self.assertEqual(result, REQUEUE)
Exemple #3
0
    def instance_id(self, value: str) -> None:  # publc.
        """Sets instance id.

        :param value: instance id
        :type value: str
        """
        if isinstance(value, str) is False:
            raise _K2hr3UserAgentError(
                'Please pass UUID as a string, not {}'.format(value))
        try:
            if value:
                uuid.UUID(value)
                self._instance_id = value
        except ValueError as error:
            raise _K2hr3UserAgentError('Invalid UUID, {} {}'.format(
                value, error))
        # Note:
        # parameter name is 'cuk' when calling r3api.
        self._params['cuk'] = self._instance_id
Exemple #4
0
    def allow_self_signed_cert(self, value: bool) -> None:  # public.
        """Sets the flag of self signed certificate or not.

        :param value: True if allow self signed certificate to use.
        :type value: bool
        """
        if isinstance(value, bool):
            self._allow_self_signed_cert = value
        else:
            raise _K2hr3UserAgentError(
                'Boolean value expected, not {}'.format(value))
Exemple #5
0
    def method(self, value: str) -> None:
        """Sets the http request method string.

        :param value: http request method string
        :type value: str
        """
        if isinstance(value, str) is True:
            LOG.debug('http request method is %s', value)
            self._method = value
        else:
            raise _K2hr3UserAgentError(
                'method should be string, not {}'.format(value))
    def error(self, value: str) -> None:  # public.
        """Sets the HTTP error.

        :param value: HTTP error
        :type value: str
        """
        # Input validation in public method should be done first.
        if isinstance(value, str) is True:
            self._error = value
        else:
            raise _K2hr3UserAgentError(
                'error should be str, not {}'.format(value))
    def code(self, value: int) -> None:  # public.
        """Sets the HTTP status code.

        :param value: HTTP status code
        :type value: int
        """
        # Input validation in public method should be done first.
        if isinstance(value, int) is True:
            self._code = value
        else:
            raise _K2hr3UserAgentError('code should be int, not {}'.format(
                type(value)))
Exemple #8
0
    def ips(self, value: str) -> None:  # public.
        """Sets ip or ips to the ipaddress list.

        :param value: ipaddress(str or list)
        :type value: object
        """
        ips = []  # type: List[str]
        if isinstance(value, list):
            ips += value
        elif isinstance(value, str):
            ips = [value]
        else:
            raise _K2hr3UserAgentError(
                'ips must be list or str, not {}'.format(value))
        for ipaddress in ips:
            if isinstance(ipaddress, str) is False:
                raise _K2hr3UserAgentError(
                    'ip must be str, not {}'.format(ipaddress))
            try:
                # https://github.com/python/cpython/blob/master/Modules/socketmodule.c#L6172
                socket.inet_pton(socket.AF_INET, ipaddress)
                self._ips += [ipaddress]
            except OSError:
                LOG.debug('not ip version4 string %s', ipaddress)
                try:
                    socket.inet_pton(socket.AF_INET6, ipaddress)
                    self._ips += [ipaddress]
                except OSError as error:
                    LOG.error('neither ip version4 nor version6 string %s %s',
                              ipaddress, error)
                    raise _K2hr3UserAgentError(
                        'ip must be valid string, not {} {}'.format(
                            ipaddress, error))
        self._ips = ips  # overwrite
        LOG.debug('ips=%s', ips)
        # Note:
        # parameter name is 'host' when calling r3api.
        self._params['host'] = json.dumps(self._ips)
Exemple #9
0
    def test_notification_endpoint_info_r3api_failed_by_exception(self):
        """Checks if info works correctly.

        NotificationEndpoint::info returns HANDLED if __call_r3api returns HANDLED.
        __call_r3api internally callses _K2hr3UserAgent::send() to call the R3 API.
        We mock the method to return False without having access to the API.
        """
        conf = K2hr3Conf(src_dir + '/etc/k2hr3_osnl.conf.sample')
        endpoint = K2hr3NotificationEndpoint(conf)
        _K2hr3UserAgent.send = MagicMock(
            side_effect=_K2hr3UserAgentError('send error'))
        with open(src_dir + '/tools/data/notifications_neutron.json') as fp:
            data = json.load(fp)
            result = endpoint.info(data['ctxt'], data['publisher_id'],
                                   data['event_type'], data['payload'],
                                   data['metadata'])
        # Ensure the__call_r3api is not called.
        self.assertEqual(result, HANDLED)
Exemple #10
0
    def validate_url(value):
        """Returns True if given string is a url.

        :param value: a url like string
        :type value: str
        :returns: True if given string is a url.
        :rtype: bool
        """
        # scheme
        try:
            scheme, url_string = value.split('://', maxsplit=2)
        except ValueError as error:
            raise _K2hr3UserAgentError(
                'scheme should contain ://, not {}'.format(value)) from error
        if scheme not in ('http', 'https'):
            raise _K2hr3UserAgentError(
                'scheme should be http or http, not {}'.format(scheme))
        else:
            LOG.debug('scheme is %s', scheme)

        matches = re.match(
            r'(?P<domain>[\w|\.]+)?(?P<port>:\d{2,5})?(?P<path>[\w|/]*)?',
            url_string)
        if matches is None:
            raise _K2hr3UserAgentError(
                'the argument seems not to be a url string, {}'.format(value))

        # domain must be resolved.
        domain = matches.group('domain')
        if domain is None:
            raise _K2hr3UserAgentError(
                'url contains no domain, {}'.format(value))
        try:
            # https://github.com/python/cpython/blob/master/Modules/socketmodule.c#L5729
            ipaddress = socket.gethostbyname(domain)
        except OSError as error:  # resolve failed
            raise _K2hr3UserAgentError('unresolved domain, {} {}'.format(
                domain, error))
        else:
            LOG.debug('%s resolved %s', domain, ipaddress)

        # path(optional)
        if matches.group('path') is None:
            raise _K2hr3UserAgentError(
                'url contains no path, {}'.format(value))
        path = matches.group('path')
        # port(optional)
        port = matches.group('port')
        LOG.debug('url=%s domain=%s port=%s path=%s', value, domain, port,
                  path)
        return True
Exemple #11
0
    def test_notification_endpoint_call_r3api_requeue_on_exception(self):
        """Checks if call_r3api works correctly.

        __call_r3api calls the _K2hr3UserAgent::send() to call the R3 API.
        We mock _K2hr3UserAgent::send() to throws a _K2hr3UserAgentError.
        If requeue_on_error is true, then the function returns HANDLED.
        """
        # Expected return_value is REQUEUE in this case.
        self.mock_method.return_value = REQUEUE
        conf = K2hr3Conf(src_dir + '/etc/k2hr3_osnl.conf.sample')
        conf.k2hr3.requeue_on_error = True
        _K2hr3UserAgent.send = MagicMock(
            side_effect=_K2hr3UserAgentError('error'))
        endpoint = K2hr3NotificationEndpoint(conf)
        with open(src_dir + '/tools/data/notifications_neutron.json') as fp:
            data = json.load(fp)
            result = endpoint.info(data['ctxt'], data['publisher_id'],
                                   data['event_type'], data['payload'],
                                   data['metadata'])
        self.assertEqual(result, REQUEUE)

        # Reset it. Default return_value is HANDLED.
        self.mock_method.return_value = HANDLED
Exemple #12
0
    def test_notification_endpoint_call_r3api_requeue_on_exception(self):
        """Checks if call_r3api works correctly.

        __call_r3api calls the _K2hr3UserAgent::send() to call the R3 API.
        We mock _K2hr3UserAgent::send() to throws a _K2hr3UserAgentError.
        If requeue_on_error is true, then the function returns HANDLED.
        """
        # Expected return_value is REQUEUE in this case.
        _K2hr3UserAgent.send = MagicMock(
            side_effect=_K2hr3UserAgentError('error'))

        conf = K2hr3Conf(conf_file_path)
        conf.k2hr3.requeue_on_error = True  # overwrites it True.
        endpoint = K2hr3NotificationEndpoint(conf)
        json_file_path = Path(
            os.sep.join(
                [here, '..', 'tools', 'data',
                 'notifications_neutron.json'])).resolve()
        with json_file_path.open() as fp:
            data = json.load(fp)
            result = endpoint.info(data['ctxt'], data['publisher_id'],
                                   data['event_type'], data['payload'],
                                   data['metadata'])
        self.assertEqual(result, REQUEUE)