Beispiel #1
0
def get_ironic_api_url():
    """Resolve Ironic API endpoint

    either from config of from Keystone catalog.
    """
    adapter_opts = {'session': _get_ironic_session()}
    # NOTE(pas-ha) force 'none' auth plugin for noauth mode
    if CONF.auth_strategy != 'keystone':
        CONF.set_override('auth_type', 'none', group='service_catalog')
    adapter_opts['auth'] = keystone.get_auth('service_catalog')

    # TODO(pas-ha) remove in Rocky
    # NOTE(pas-ha) if both set, the new options win
    if CONF.conductor.api_url and not CONF.service_catalog.endpoint_override:
        adapter_opts['endpoint_override'] = CONF.conductor.api_url
    try:
        ironic_api = keystone.get_endpoint('service_catalog', **adapter_opts)
    except (exception.KeystoneFailure, exception.CatalogNotFound,
            exception.KeystoneUnauthorized) as e:
        raise exception.InvalidParameterValue(
            _("Couldn't get the URL of the Ironic API service from the "
              "configuration file or keystone catalog. Keystone error: "
              "%s") % str(e))
    # NOTE: we should strip '/' from the end because it might be used in
    # hardcoded ramdisk script
    ironic_api = ironic_api.rstrip('/')
    return ironic_api
Beispiel #2
0
    def wrapper(self, *args, **kwargs):
        """Wrapper around methods calls.

        :param image_href: href that describes the location of an image
        """

        if self.client:
            return func(self, *args, **kwargs)

        global _GLANCE_SESSION
        if not _GLANCE_SESSION:
            _GLANCE_SESSION = keystone.get_session('glance')

        # NOTE(pas-ha) glanceclient uses Adapter-based SessionClient,
        # so we can pass session and auth separately, makes things easier
        service_auth = keystone.get_auth('glance')

        self.endpoint = keystone.get_endpoint('glance',
                                              session=_GLANCE_SESSION,
                                              auth=service_auth)

        user_auth = None
        # NOTE(pas-ha) our ContextHook removes context.auth_token in noauth
        # case, so when ironic is in noauth but glance is not, we will not
        # enter the next if-block and use auth from [glance] config section
        if self.context.auth_token:
            user_auth = keystone.get_service_auth(self.context, self.endpoint,
                                                  service_auth)
        self.client = client.Client(2,
                                    session=_GLANCE_SESSION,
                                    auth=user_auth or service_auth,
                                    endpoint_override=self.endpoint,
                                    global_request_id=self.context.global_id)
        return func(self, *args, **kwargs)
Beispiel #3
0
def get_client(token=None, context=None, auth_from_config=False):
    """Retrieve a neutron client connection.

    :param context: request context,
                    instance of ironic.common.context.RequestContext
    :param auth_from_config: (boolean) When True, use auth values from
                          conf parameters
    :returns: A neutron client.
    """
    if not context:
        context = ironic_context.RequestContext(auth_token=token)
    session = _get_neutron_session()
    service_auth = keystone.get_auth('neutron')
    endpoint = keystone.get_endpoint('neutron',
                                     session=session,
                                     auth=service_auth)

    user_auth = None
    if (not auth_from_config and CONF.neutron.auth_type != 'none'
            and context.auth_token):
        user_auth = keystone.get_service_auth(context, endpoint, service_auth)

    sess = keystone.get_session('neutron',
                                timeout=CONF.neutron.timeout,
                                auth=user_auth or service_auth)
    conn = openstack.connection.Connection(session=sess, oslo_conf=CONF)

    return conn.global_request(context.global_id).network
Beispiel #4
0
def get_client(token=None, context=None):
    if not context:
        context = ironic_context.RequestContext(auth_token=token)
    # NOTE(pas-ha) neutronclient supports passing both session
    # and the auth to client separately, makes things easier
    session = _get_neutron_session()
    service_auth = keystone.get_auth('neutron')

    # TODO(pas-ha) remove in Rocky, always simply load from config
    # 'noauth' then would correspond to 'auth_type=none' and
    # 'endpoint_override'
    adapter_params = {}
    if (CONF.neutron.auth_strategy == 'noauth'
            and CONF.neutron.auth_type is None):
        CONF.set_override('auth_type', 'none', group='neutron')
        if not CONF.neutron.endpoint_override:
            adapter_params['endpoint_override'] = (CONF.neutron.url
                                                   or DEFAULT_NEUTRON_URL)
    else:
        if CONF.neutron.url and not CONF.neutron.endpoint_override:
            adapter_params['endpoint_override'] = CONF.neutron.url
    endpoint = keystone.get_endpoint('neutron',
                                     session=session,
                                     auth=service_auth,
                                     **adapter_params)

    user_auth = None
    if CONF.neutron.auth_type != 'none' and context.auth_token:
        user_auth = keystone.get_service_auth(context, endpoint, service_auth)
    return clientv20.Client(session=session,
                            auth=user_auth or service_auth,
                            endpoint_override=endpoint,
                            retries=CONF.neutron.retries,
                            global_request_id=context.global_id,
                            timeout=CONF.neutron.request_timeout)
Beispiel #5
0
def get_client(context):
    """Get a cinder client connection.

    :param context: request context,
                    instance of ironic.common.context.RequestContext
    :returns: A cinder client.
    """
    service_auth = keystone.get_auth('cinder')
    session = _get_cinder_session()

    # TODO(pas-ha) remove in Rocky
    adapter_opts = {}
    # NOTE(pas-ha) new option must always win if set
    if CONF.cinder.url and not CONF.cinder.endpoint_override:
        adapter_opts['endpoint_override'] = CONF.cinder.url

    # TODO(pas-ha) use versioned endpoint data to select required
    # cinder api version
    cinder_url = keystone.get_endpoint('cinder',
                                       session=session,
                                       auth=service_auth,
                                       **adapter_opts)
    # TODO(pas-ha) investigate possibility of passing a user context here,
    # similar to what neutron/glance-related code does
    # NOTE(pas-ha) cinderclient has both 'connect_retries' (passed to
    # ksa.Adapter) and 'retries' (used in its subclass of ksa.Adapter) options.
    # The first governs retries on establishing the HTTP connection,
    # the second governs retries on OverLimit exceptions from API.
    # The description of [cinder]/retries fits the first,
    # so this is what we pass.
    return client.Client(session=session,
                         auth=service_auth,
                         endpoint_override=cinder_url,
                         connect_retries=CONF.cinder.retries,
                         global_request_id=context.global_id)
Beispiel #6
0
def _get_conf_client(context):
    """Retrieve a neutron client connection using conf parameters.

    :param context: request context,
                    instance of ironic.common.context.RequestContext
    :returns: A neutron client.
    """

    auth = ks_loading.load_auth_from_conf_options(CONF, 'neutron')
    session = ks_loading.load_session_from_conf_options(CONF,
                                                        'neutron',
                                                        auth=auth)
    endpoint = keystone.get_endpoint('neutron', session=session, auth=auth)
    return clientv20.Client(session=session,
                            auth=auth,
                            endpoint_override=endpoint,
                            retries=CONF.neutron.retries,
                            global_request_id=context.global_id,
                            timeout=CONF.neutron.request_timeout)
Beispiel #7
0
def get_client(token=None, context=None):
    if not context:
        context = ironic_context.RequestContext(auth_token=token)
    # NOTE(pas-ha) neutronclient supports passing both session
    # and the auth to client separately, makes things easier
    session = _get_neutron_session()
    service_auth = keystone.get_auth('neutron')

    endpoint = keystone.get_endpoint('neutron', session=session,
                                     auth=service_auth)

    user_auth = None
    if CONF.neutron.auth_type != 'none' and context.auth_token:
        user_auth = keystone.get_service_auth(context, endpoint, service_auth)
    return clientv20.Client(session=session,
                            auth=user_auth or service_auth,
                            endpoint_override=endpoint,
                            retries=CONF.neutron.retries,
                            global_request_id=context.global_id,
                            timeout=CONF.neutron.request_timeout)
Beispiel #8
0
def _get_client(context):
    """Helper to get inspector client instance."""
    # NOTE(pas-ha) remove in Rocky
    if CONF.auth_strategy != 'keystone':
        CONF.set_override('auth_type', 'none', group='inspector')
    service_auth = keystone.get_auth('inspector')
    session = _get_inspector_session(auth=service_auth)
    adapter_params = {}
    if CONF.inspector.service_url and not CONF.inspector.endpoint_override:
        adapter_params['endpoint_override'] = CONF.inspector.service_url
    inspector_url = keystone.get_endpoint('inspector', session=session,
                                          **adapter_params)
    # TODO(pas-ha) investigate possibility of passing user context here,
    # similar to what neutron/glance-related code does
    # NOTE(pas-ha) ironic-inspector-client has no Adaper-based
    # SessionClient, so we'll resolve inspector API form adapter loaded
    # form config options
    # TODO(pas-ha) rewrite when inspectorclient is based on ksa Adapter,
    #              also add global_request_id to the call
    return client.ClientV1(api_version=INSPECTOR_API_VERSION,
                           session=session,
                           inspector_url=inspector_url)
Beispiel #9
0
    def __init__(self):
        """Initialize the connection with swift

        :raises: ConfigInvalid if required keystone authorization credentials
         with swift are missing.
        """
        params = {'retries': CONF.swift.swift_max_retries}
        # NOTE(pas-ha) swiftclient still (as of 3.3.0) does not use
        # (adapter-based) SessionClient, and uses the passed in session
        # only to resolve endpoint and get a token,
        # but not to make further requests to Swift itself (LP 1736135).
        # Thus we need to deconstruct back all the adapter- and
        # session-related args as loaded by keystoneauth from config
        # to pass them to the client explicitly.
        # TODO(pas-ha) re-write this when swiftclient is brought on par
        # with other OS clients re auth plugins, sessions and adapters
        # support.
        # TODO(pas-ha) pass the context here and use token from context
        # with service auth
        params['session'] = session = get_swift_session()
        endpoint = keystone.get_endpoint('swift', session=session)
        params['os_options'] = {'object_storage_url': endpoint}
        # deconstruct back session-related options
        params['timeout'] = session.timeout
        if session.verify is False:
            params['insecure'] = True
        elif isinstance(session.verify, str):
            params['cacert'] = session.verify
        if session.cert:
            # NOTE(pas-ha) although setting cert as path to single file
            # with both client cert and key is supported by Session,
            # keystoneauth loading always sets the session.cert
            # as tuple of cert and key.
            params['cert'], params['cert_key'] = session.cert

        self.connection = swift_client.Connection(**params)
Beispiel #10
0
    def swift_temp_url(self, image_info):
        """Generate a no-auth Swift temporary URL.

        This function will generate (or return the cached one if temp URL
        cache is enabled) the temporary Swift URL using the image
        id from Glance and the config options: 'swift_endpoint_url',
        'swift_api_version', 'swift_account' and 'swift_container'.
        The temporary URL will be valid for 'swift_temp_url_duration' seconds.
        This allows Ironic to download a Glance image without passing around
        an auth_token.

        :param image_info: The return from a GET request to Glance for a
            certain image_id. Should be a dictionary, with keys like 'name' and
            'checksum'. See
            https://docs.openstack.org/glance/latest/user/glanceapi.html for
            examples.
        :returns: A signed Swift URL from which an image can be downloaded,
            without authentication.

        :raises: InvalidParameterValue if Swift config options are not set
            correctly.
        :raises: MissingParameterValue if a required parameter is not set.
        :raises: ImageUnacceptable if the image info from Glance does not
            have an image ID.
        """
        self._validate_temp_url_config()

        if ('id' not in image_info
                or not uuidutils.is_uuid_like(image_info['id'])):
            raise exception.ImageUnacceptable(
                _('The given image info does not have a valid image id: %s') %
                image_info)

        image_id = image_info['id']

        url_fragments = {
            'api_version': CONF.glance.swift_api_version,
            'container': self._get_swift_container(image_id),
            'object_id': image_id
        }

        endpoint_url = CONF.glance.swift_endpoint_url
        if not endpoint_url:
            swift_session = swift.get_swift_session()
            try:
                endpoint_url = keystone.get_endpoint('swift',
                                                     session=swift_session)
            except exception.CatalogNotFound:
                raise exception.MissingParameterValue(
                    _('Swift temporary URLs require a Swift endpoint URL, '
                      'but it was not found in the service catalog. You must '
                      'provide "swift_endpoint_url" as a config option.'))

        # Strip /v1/AUTH_%(tenant_id)s, if present
        endpoint_url = re.sub('/v1/AUTH_[^/]+/?$', '', endpoint_url)

        key = CONF.glance.swift_temp_url_key
        account = CONF.glance.swift_account
        if not account:
            swift_session = swift.get_swift_session()
            auth_ref = swift_session.auth.get_auth_ref(swift_session)
            account = 'AUTH_%s' % auth_ref.project_id

        if not key:
            swift_api = swift.SwiftAPI()
            key_header = 'x-account-meta-temp-url-key'
            key = swift_api.connection.head_account().get(key_header)

        if not key:
            raise exception.MissingParameterValue(
                _('Swift temporary URLs require a shared secret to be '
                  'created. You must provide "swift_temp_url_key" as a '
                  'config option or pre-generate the key on the project '
                  'used to access Swift.'))

        url_fragments['account'] = account
        template = '/{api_version}/{account}/{container}/{object_id}'

        url_path = template.format(**url_fragments)

        return self._generate_temp_url(
            path=url_path,
            seconds=CONF.glance.swift_temp_url_duration,
            key=key,
            method='GET',
            endpoint=endpoint_url,
            image_id=image_id)