Esempio n. 1
0
def nova(context):
    args = {
        'auth_url': CONF.keystone_url,
        'auth_token': context.auth_token,
        # NOTE(ft): These parameters are not used for authentification,
        # but are required by novaclient < v2.18 which may be installed in
        # Icehouse deployment
        'username': None,
        'api_key': None,
        'project_id': None,
    }
    global _novaclient_vertion, _nova_service_type
    bypass_url = _url_for(context, service_type=_nova_service_type)
    if not bypass_url and _nova_service_type == 'computev21':
        # NOTE(ft): partial compatibility with pre Kilo OS releases:
        # if computev21 isn't provided by Nova, use compute instead
        logger.warning(_LW("Nova server doesn't support v2.1, use v2 instead. "
                           "A lot of useful EC2 compliant instance properties "
                           "will be unavailable."))
        _nova_service_type = 'compute'
        return nova(context)
    try:
        return novaclient.Client(_novaclient_vertion, bypass_url=bypass_url,
                                 **args)
    except nova_exception.UnsupportedVersion:
        if _novaclient_vertion == '2':
            raise
        # NOTE(ft): partial compatibility with Nova client w/o microversion
        # support
        logger.warning(_LW("Nova client doesn't support v2.3, use v2 instead. "
                           "A lot of useful EC2 compliant instance properties "
                           "will be unavailable."))
        _novaclient_vertion = '2'
        return nova(context)
 def _run_cleanups(self, cleanups):
     for function, args, kwargs in reversed(cleanups):
         try:
             function(*args, **kwargs)
         except Exception:
             if inspect.ismethod(function):
                 name = '%s.%s.%s' % (function.im_class.__module__,
                                      function.im_class.__name__,
                                      function.__name__)
             elif inspect.isfunction(function):
                 name = '%s.%s' % (function.__module__, function.__name__)
             else:
                 name = '%s.%s' % (function.__class__.__module__,
                                   function.__class__.__name__)
             formatted_args = ''
             args_string = ', '.join([repr(arg) for arg in args])
             kwargs_string = ', '.join(
                 ['%s=%r' % (key, value) for key, value in kwargs.items()])
             if args_string:
                 formatted_args = args_string
             if kwargs_string:
                 if formatted_args:
                     formatted_args += ', '
                 formatted_args += kwargs_string
             LOG.warning(_LW('Error cleaning up %(name)s(%(args)s)') % {
                 'name': name,
                 'args': formatted_args
             },
                         exc_info=True)
             pass
Esempio n. 3
0
    def __init__(self,
                 user_id,
                 project_id,
                 request_id=None,
                 is_admin=None,
                 remote_address=None,
                 auth_token=None,
                 user_name=None,
                 project_name=None,
                 overwrite=True,
                 service_catalog=None,
                 api_version=None,
                 is_os_admin=None,
                 **kwargs):
        """Parameters

            :param overwrite: Set to False to ensure that the greenthread local
                copy of the index is not overwritten.


            :param kwargs: Extra arguments that might be present, but we ignore
                because they possibly came in from older rpc messages.
        """
        user = kwargs.pop('user', None)
        tenant = kwargs.pop('tenant', None)
        super(RequestContext,
              self).__init__(auth_token=auth_token,
                             user=user_id or user,
                             tenant=project_id or tenant,
                             is_admin=is_admin,
                             request_id=request_id,
                             resource_uuid=kwargs.pop('resource_uuid', None),
                             overwrite=overwrite)
        # oslo_context's RequestContext.to_dict() generates this field, we can
        # safely ignore this as we don't use it.
        kwargs.pop('user_identity', None)
        if kwargs:
            LOG.warning(
                _LW('Arguments dropped when creating context: %s') %
                str(kwargs))

        self.user_id = user_id
        self.project_id = project_id
        self.remote_address = remote_address
        timestamp = timeutils.utcnow()
        if isinstance(timestamp, six.string_types):
            timestamp = timeutils.parse_strtime(timestamp)
        self.timestamp = timestamp

        self.service_catalog = service_catalog
        if self.service_catalog is None:
            # if list is empty or none
            self.service_catalog = []

        self.user_name = user_name
        self.project_name = project_name
        self.is_admin = is_admin
        # TODO(ft): call policy.check_is_admin if is_admin is None
        self.is_os_admin = is_os_admin
        self.api_version = api_version
Esempio n. 4
0
 def _run_cleanups(self, cleanups):
     for function, args, kwargs in reversed(cleanups):
         try:
             function(*args, **kwargs)
         except Exception:
             if inspect.ismethod(function):
                 name = '%s.%s.%s' % (function.im_class.__module__,
                                      function.im_class.__name__,
                                      function.__name__)
             elif inspect.isfunction(function):
                 name = '%s.%s' % (function.__module__,
                                   function.__name__)
             else:
                 name = '%s.%s' % (function.__class__.__module__,
                                   function.__class__.__name__)
             formatted_args = ''
             args_string = ', '.join([repr(arg) for arg in args])
             kwargs_string = ', '.join([
                 '%s=%r' % (key, value) for key, value in kwargs.items()
             ])
             if args_string:
                 formatted_args = args_string
             if kwargs_string:
                 if formatted_args:
                     formatted_args += ', '
                 formatted_args += kwargs_string
             LOG.warning(
                 _LW('Error cleaning up %(name)s(%(args)s)') %
                 {'name': name, 'args': formatted_args},
                 exc_info=True)
             pass
Esempio n. 5
0
    def delayed_create(context, image, name, os_instance):
        try:
            os_instance.stop()

            # wait instance for really stopped
            start_time = time.time()
            while os_instance.status != 'SHUTOFF':
                time.sleep(1)
                os_instance.get()
                # NOTE(yamahata): timeout and error. 1 hour for now for safety.
                #                 Is it too short/long?
                #                 Or is there any better way?
                timeout = 1 * 60 * 60
                if time.time() > start_time + timeout:
                    err = (_("Couldn't stop instance within %d sec") % timeout)
                    raise exception.EC2Exception(message=err)

            # NOTE(ft): create an image with ec2_id metadata to let other code
            # link os and db objects in race conditions
            os_image_id = os_instance.create_image(
                name, metadata={'ec2_id': image['id']})
            image['os_id'] = os_image_id
            db_api.update_item(context, image)
        except Exception:
            LOG.exception(_LE('Failed to complete image %s creation'),
                          image.id)
            try:
                image['state'] = 'failed'
                db_api.update_item(context, image)
            except Exception:
                LOG.warning(_LW("Couldn't set 'failed' state for db image %s"),
                            image.id,
                            exc_info=True)

        try:
            os_instance.start()
        except Exception:
            LOG.warning(_LW('Failed to start instance %(i_id)s after '
                            'completed creation of image %(image_id)s'), {
                                'i_id': instance['id'],
                                'image_id': image['id']
                            },
                        exc_info=True)
Esempio n. 6
0
def _get_nova_api_version(context):
    client = novaclient.Client(REQUIRED_NOVA_API_VERSION,
                               session=context.session,
                               service_type=CONF.nova_service_type)

    required = nova_api_versions.APIVersion(REQUIRED_NOVA_API_MICROVERSION)
    current = client.versions.get_current()
    if not current:
        logger.warning(
            _LW('Could not check Nova API version because no version '
                'was found in Nova version list for url %(url)s of service '
                'type "%(service_type)s". '
                'Use v%(required_api_version)s Nova API.'), {
                    'url': client.client.get_endpoint(),
                    'service_type': CONF.nova_service_type,
                    'required_api_version': REQUIRED_NOVA_API_MICROVERSION
                })
        return REQUIRED_NOVA_API_MICROVERSION
    if current.id != REQUIRED_NOVA_API_VERSION_ID:
        logger.warning(
            _LW('Specified "%s" Nova service type does not support v2.1 API. '
                'A lot of useful EC2 compliant instance properties '
                'will be unavailable.'), CONF.nova_service_type)
        return LEGACY_NOVA_API_VERSION
    if (nova_api_versions.APIVersion(current.version) < required):
        logger.warning(
            _LW('Nova support v%(nova_api_version)s, '
                'but v%(required_api_version)s is required. '
                'A lot of useful EC2 compliant instance properties '
                'will be unavailable.'), {
                    'nova_api_version': current.version,
                    'required_api_version': REQUIRED_NOVA_API_MICROVERSION
                })
        return current.version
    logger.info(
        _LI('Provided Nova API version is  v%(nova_api_version)s, '
            'used one is v%(required_api_version)s'), {
                'nova_api_version': current.version,
                'required_api_version': (REQUIRED_NOVA_API_MICROVERSION)
            })
    return REQUIRED_NOVA_API_MICROVERSION
Esempio n. 7
0
    def delayed_create(context, image, name, os_instance):
        try:
            os_instance.stop()

            # wait instance for really stopped
            start_time = time.time()
            while os_instance.status != 'SHUTOFF':
                time.sleep(1)
                os_instance.get()
                # NOTE(yamahata): timeout and error. 1 hour for now for safety.
                #                 Is it too short/long?
                #                 Or is there any better way?
                timeout = 1 * 60 * 60
                if time.time() > start_time + timeout:
                    err = (_("Couldn't stop instance within %d sec") % timeout)
                    raise exception.EC2Exception(message=err)

            # NOTE(ft): create an image with ec2_id metadata to let other code
            # link os and db objects in race conditions
            os_image_id = os_instance.create_image(
                name, metadata={'ec2_id': image['id']})
            image['os_id'] = os_image_id
            db_api.update_item(context, image)
        except Exception:
            LOG.exception(_LE('Failed to complete image %s creation'),
                          image.id)
            try:
                image['state'] = 'failed'
                db_api.update_item(context, image)
            except Exception:
                LOG.warning(_LW("Couldn't set 'failed' state for db image %s"),
                            image.id, exc_info=True)

        try:
            os_instance.start()
        except Exception:
            LOG.warning(_LW('Failed to start instance %(i_id)s after '
                            'completed creation of image %(image_id)s'),
                        {'i_id': instance['id'],
                         'image_id': image['id']},
                        exc_info=True)
Esempio n. 8
0
def _get_nova_api_version(context):
    client = novaclient.Client(REQUIRED_NOVA_API_VERSION,
                               session=context.session,
                               service_type=CONF.nova_service_type)

    required = nova_api_versions.APIVersion(REQUIRED_NOVA_API_MICROVERSION)
    current = client.versions.get_current()
    if not current:
        logger.warning(
            _LW('Could not check Nova API version because no version '
                'was found in Nova version list for url %(url)s of service '
                'type "%(service_type)s". '
                'Use v%(required_api_version)s Nova API.'),
            {'url': client.client.get_endpoint(),
             'service_type': CONF.nova_service_type,
             'required_api_version': REQUIRED_NOVA_API_MICROVERSION})
        return REQUIRED_NOVA_API_MICROVERSION
    if current.id != REQUIRED_NOVA_API_VERSION_ID:
        logger.warning(
            _LW('Specified "%s" Nova service type does not support v2.1 API. '
                'A lot of useful EC2 compliant instance properties '
                'will be unavailable.'),
            CONF.nova_service_type)
        return LEGACY_NOVA_API_VERSION
    if (nova_api_versions.APIVersion(current.version) < required):
        logger.warning(
            _LW('Nova support v%(nova_api_version)s, '
                'but v%(required_api_version)s is required. '
                'A lot of useful EC2 compliant instance properties '
                'will be unavailable.'),
            {'nova_api_version': current.version,
             'required_api_version': REQUIRED_NOVA_API_MICROVERSION})
        return current.version
    logger.info(_LI('Provided Nova API version is  v%(nova_api_version)s, '
                    'used one is v%(required_api_version)s'),
                {'nova_api_version': current.version,
                 'required_api_version': (
                        REQUIRED_NOVA_API_MICROVERSION)})
    return REQUIRED_NOVA_API_MICROVERSION
def nova(context):
    args = {
        'auth_url': CONF.keystone_url,
        'auth_token': context.auth_token,
        # NOTE(ft): These parameters are not used for authentification,
        # but are required by novaclient < v2.18 which may be installed in
        # Icehouse deployment
        'username': None,
        'api_key': None,
        'project_id': None,
        'insecure': CONF.ssl_insecure,
        'cacert': CONF.ssl_ca_file
    }
    global _novaclient_vertion, _nova_service_type
    bypass_url = _url_for(context, service_type=_nova_service_type)
    if not bypass_url and _nova_service_type == 'computev21':
        # NOTE(ft): partial compatibility with pre Kilo OS releases:
        # if computev21 isn't provided by Nova, use compute instead
        logger.warning(
            _LW("Nova server doesn't support v2.1, use v2 instead. "
                "A lot of useful EC2 compliant instance properties "
                "will be unavailable."))
        _nova_service_type = 'compute'
        return nova(context)
    try:
        return novaclient.Client(_novaclient_vertion,
                                 bypass_url=bypass_url,
                                 **args)
    except nova_exception.UnsupportedVersion:
        if _novaclient_vertion == '2':
            raise
        # NOTE(ft): partial compatibility with Nova client w/o microversion
        # support
        logger.warning(
            _LW("Nova client doesn't support v2.3, use v2 instead. "
                "A lot of useful EC2 compliant instance properties "
                "will be unavailable."))
        _novaclient_vertion = '2'
        return nova(context)
Esempio n. 10
0
    def __init__(self, user_id, project_id, request_id=None,
                 is_admin=None, remote_address=None,
                 auth_token=None, user_name=None, project_name=None,
                 overwrite=True, service_catalog=None, api_version=None,
                 is_os_admin=None, **kwargs):
        """Parameters

            :param overwrite: Set to False to ensure that the greenthread local
                copy of the index is not overwritten.


            :param kwargs: Extra arguments that might be present, but we ignore
                because they possibly came in from older rpc messages.
        """
        user = kwargs.pop('user', None)
        tenant = kwargs.pop('tenant', None)
        super(RequestContext, self).__init__(
            auth_token=auth_token,
            user=user_id or user,
            tenant=project_id or tenant,
            is_admin=is_admin,
            request_id=request_id,
            resource_uuid=kwargs.pop('resource_uuid', None),
            overwrite=overwrite)
        # oslo_context's RequestContext.to_dict() generates this field, we can
        # safely ignore this as we don't use it.
        kwargs.pop('user_identity', None)
        self.session = kwargs.pop('session', None)
        if kwargs:
            LOG.warning(_LW('Arguments dropped when creating context: %s') %
                        str(kwargs))

        self.user_id = user_id
        self.project_id = project_id
        self.remote_address = remote_address
        timestamp = timeutils.utcnow()
        if isinstance(timestamp, six.string_types):
            timestamp = timeutils.parse_strtime(timestamp)
        self.timestamp = timestamp

        self.service_catalog = service_catalog
        if self.service_catalog is None:
            # if list is empty or none
            self.service_catalog = []

        self.user_name = user_name
        self.project_name = project_name
        self.is_admin = is_admin
        # TODO(ft): call policy.check_is_admin if is_admin is None
        self.is_os_admin = is_os_admin
        self.api_version = api_version
Esempio n. 11
0
    def _proxy_request(self, req, requester):
        headers = self._build_proxy_request_headers(requester)
        nova_ip_port = '%s:%s' % (CONF.metadata.nova_metadata_ip,
                                  CONF.metadata.nova_metadata_port)
        url = urlparse.urlunsplit((
            CONF.metadata.nova_metadata_protocol,
            nova_ip_port,
            req.path_info,
            req.query_string,
            ''))

        h = httplib2.Http(
            ca_certs=CONF.metadata.auth_ca_cert,
            disable_ssl_certificate_validation=(
                    CONF.metadata.nova_metadata_insecure)
        )
        if (CONF.metadata.nova_client_cert and
                CONF.metadata.nova_client_priv_key):
            h.add_certificate(CONF.metadata.nova_client_priv_key,
                              CONF.metadata.nova_client_cert,
                              nova_ip_port)
        resp, content = h.request(url, method=req.method, headers=headers,
                                  body=req.body)

        if resp.status == 200:
            LOG.debug(str(resp))
            req.response.content_type = resp['content-type']
            req.response.body = content
            return req.response
        elif resp.status == 403:
            LOG.warn(_LW(
                'The remote metadata server responded with Forbidden. This '
                'response usually occurs when shared secrets do not match.'
            ))
            return webob.exc.HTTPForbidden()
        elif resp.status == 400:
            return webob.exc.HTTPBadRequest()
        elif resp.status == 404:
            return webob.exc.HTTPNotFound()
        elif resp.status == 409:
            return webob.exc.HTTPConflict()
        elif resp.status == 500:
            msg = _(
                'Remote metadata server experienced an internal server error.'
            )
            LOG.warn(msg)
            return webob.exc.HTTPInternalServerError(
                explanation=six.text_type(msg))
        else:
            raise Exception(_('Unexpected response code: %s') % resp.status)
def _url_for(context, **kwargs):
    service_type = kwargs['service_type']
    if service_type == 'compute':
        url = CONF.service_catalog.compute
        url = url.replace('TENANT_ID', context.project_id)
    elif service_type == 'image':
        url = CONF.service_catalog.image
    elif service_type == 'network':
        url = CONF.service_catalog.network
    elif service_type == 'volumev2':
        url = CONF.service_catalog.volumev2
        url = url.replace('TENANT_ID', context.project_id)
    else:
        logger.warning(_LW("Unknown service type in JCS Layer."))
    return url
Esempio n. 13
0
    def _unpack_request_attributes(self, req):
        os_instance_id = req.headers.get('X-Instance-ID')
        project_id = req.headers.get('X-Tenant-ID')
        signature = req.headers.get('X-Instance-ID-Signature')
        remote_ip = req.headers.get('X-Forwarded-For')

        if not remote_ip:
            raise exception.EC2MetadataInvalidAddress()

        if os_instance_id is None:
            msg = _('X-Instance-ID header is missing from request.')
        elif project_id is None:
            msg = _('X-Tenant-ID header is missing from request.')
        elif not isinstance(os_instance_id, six.string_types):
            msg = _('Multiple X-Instance-ID headers found within request.')
        elif not isinstance(project_id, six.string_types):
            msg = _('Multiple X-Tenant-ID headers found within request.')
        else:
            msg = None

        if msg:
            raise webob.exc.HTTPBadRequest(explanation=msg)

        expected_signature = hmac.new(
            CONF.metadata.metadata_proxy_shared_secret, os_instance_id,
            hashlib.sha256).hexdigest()

        if not utils.constant_time_compare(expected_signature, signature):
            LOG.warning(
                _LW('X-Instance-ID-Signature: %(signature)s does '
                    'not match the expected value: '
                    '%(expected_signature)s for id: '
                    '%(instance_id)s. Request From: '
                    '%(remote_ip)s'), {
                        'signature': signature,
                        'expected_signature': expected_signature,
                        'instance_id': os_instance_id,
                        'remote_ip': remote_ip
                    })

            msg = _('Invalid proxy request signature.')
            raise webob.exc.HTTPForbidden(explanation=msg)

        return os_instance_id, project_id, remote_ip
Esempio n. 14
0
    def _unpack_request_attributes(self, req):
        os_instance_id = req.headers.get('X-Instance-ID')
        project_id = req.headers.get('X-Tenant-ID')
        signature = req.headers.get('X-Instance-ID-Signature')
        remote_ip = req.headers.get('X-Forwarded-For')

        if not remote_ip:
            raise exception.EC2MetadataInvalidAddress()

        if os_instance_id is None:
            msg = _('X-Instance-ID header is missing from request.')
        elif project_id is None:
            msg = _('X-Tenant-ID header is missing from request.')
        elif not isinstance(os_instance_id, six.string_types):
            msg = _('Multiple X-Instance-ID headers found within request.')
        elif not isinstance(project_id, six.string_types):
            msg = _('Multiple X-Tenant-ID headers found within request.')
        else:
            msg = None

        if msg:
            raise webob.exc.HTTPBadRequest(explanation=msg)

        expected_signature = hmac.new(
            CONF.metadata.metadata_proxy_shared_secret,
            os_instance_id,
            hashlib.sha256).hexdigest()

        if not utils.constant_time_compare(expected_signature, signature):
            LOG.warning(_LW(
                            'X-Instance-ID-Signature: %(signature)s does '
                            'not match the expected value: '
                            '%(expected_signature)s for id: '
                            '%(instance_id)s. Request From: '
                            '%(remote_ip)s'),
                        {'signature': signature,
                         'expected_signature': expected_signature,
                         'instance_id': os_instance_id,
                         'remote_ip': remote_ip})

            msg = _('Invalid proxy request signature.')
            raise webob.exc.HTTPForbidden(explanation=msg)

        return os_instance_id, project_id, remote_ip
Esempio n. 15
0
    def _validate_signature(self, signature, requester_id, requester_ip):
        expected_signature = hmac.new(
            CONF.metadata.metadata_proxy_shared_secret.encode("utf-8"),
            requester_id.encode(),
            hashlib.sha256).hexdigest()

        if not (signature and
                utils.constant_time_compare(expected_signature, signature)):
            LOG.warning(_LW(
                            'X-Instance-ID-Signature: %(signature)s does '
                            'not match the expected value: '
                            '%(expected_signature)s for id: '
                            '%(requester_id)s. Request From: '
                            '%(requester_ip)s'),
                        {'signature': signature,
                         'expected_signature': expected_signature,
                         'requester_id': requester_id,
                         'requester_ip': requester_ip})

            msg = _('Invalid proxy request signature.')
            raise webob.exc.HTTPForbidden(explanation=msg)