Adopts keystoneauth with glance client.
Migrate Glance client to Keystonesuth to make it consistent with Cinder and Neutron clients. Note: We still use the api_servers variable, rather than fetching endpoints from the service catalog. This change is needed to enable the use of service token with Glance client. Related to blueprint use-service-tokens-pike Change-Id: I02be31bbe2de54c69210934b234ed380daca4fda Co-Authored-By: Pushkar Umaranikar <pushkar.umaranikar@intel.com>
This commit is contained in:

committed by
Eric Fried

parent
3d84232d7b
commit
b277b10df6
@@ -60,7 +60,6 @@ from nova.conf import service
|
|||||||
from nova.conf import service_token
|
from nova.conf import service_token
|
||||||
from nova.conf import servicegroup
|
from nova.conf import servicegroup
|
||||||
from nova.conf import spice
|
from nova.conf import spice
|
||||||
from nova.conf import ssl
|
|
||||||
from nova.conf import upgrade_levels
|
from nova.conf import upgrade_levels
|
||||||
from nova.conf import vendordata
|
from nova.conf import vendordata
|
||||||
from nova.conf import vmware
|
from nova.conf import vmware
|
||||||
@@ -112,7 +111,6 @@ service.register_opts(CONF)
|
|||||||
service_token.register_opts(CONF)
|
service_token.register_opts(CONF)
|
||||||
servicegroup.register_opts(CONF)
|
servicegroup.register_opts(CONF)
|
||||||
spice.register_opts(CONF)
|
spice.register_opts(CONF)
|
||||||
ssl.register_opts(CONF)
|
|
||||||
upgrade_levels.register_opts(CONF)
|
upgrade_levels.register_opts(CONF)
|
||||||
vendordata.register_opts(CONF)
|
vendordata.register_opts(CONF)
|
||||||
vmware.register_opts(CONF)
|
vmware.register_opts(CONF)
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from keystoneauth1 import loading as ks_loading
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
|
||||||
glance_group = cfg.OptGroup(
|
glance_group = cfg.OptGroup(
|
||||||
@@ -34,14 +35,6 @@ Possible values:
|
|||||||
|
|
||||||
* A list of any fully qualified url of the form "scheme://hostname:port[/path]"
|
* A list of any fully qualified url of the form "scheme://hostname:port[/path]"
|
||||||
(i.e. "http://10.0.1.0:9292" or "https://my.glance.server/image").
|
(i.e. "http://10.0.1.0:9292" or "https://my.glance.server/image").
|
||||||
"""),
|
|
||||||
cfg.BoolOpt('api_insecure',
|
|
||||||
default=False,
|
|
||||||
help="""
|
|
||||||
Enable insecure SSL (https) requests to glance.
|
|
||||||
|
|
||||||
This setting can be used to turn off verification of the glance server
|
|
||||||
certificate against the certificate authorities.
|
|
||||||
"""),
|
"""),
|
||||||
cfg.IntOpt('num_retries',
|
cfg.IntOpt('num_retries',
|
||||||
default=0,
|
default=0,
|
||||||
@@ -142,6 +135,23 @@ def register_opts(conf):
|
|||||||
conf.register_group(glance_group)
|
conf.register_group(glance_group)
|
||||||
conf.register_opts(glance_opts, group=glance_group)
|
conf.register_opts(glance_opts, group=glance_group)
|
||||||
|
|
||||||
|
deprecated = {
|
||||||
|
'insecure': [cfg.DeprecatedOpt('api_insecure',
|
||||||
|
group=glance_group.name)],
|
||||||
|
'cafile': [cfg.DeprecatedOpt('ca_file',
|
||||||
|
group="ssl")],
|
||||||
|
'certfile': [cfg.DeprecatedOpt('cert_file',
|
||||||
|
group="ssl")],
|
||||||
|
'keyfile': [cfg.DeprecatedOpt('key_file',
|
||||||
|
group="ssl")],
|
||||||
|
}
|
||||||
|
ks_loading.register_session_conf_options(conf, glance_group.name,
|
||||||
|
deprecated)
|
||||||
|
|
||||||
|
|
||||||
def list_opts():
|
def list_opts():
|
||||||
return {glance_group: glance_opts}
|
return {
|
||||||
|
glance_group: (
|
||||||
|
glance_opts +
|
||||||
|
ks_loading.get_session_conf_options())
|
||||||
|
}
|
||||||
|
@@ -1,25 +0,0 @@
|
|||||||
# Copyright 2016 OpenStack Foundation
|
|
||||||
# All Rights Reserved.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
from oslo_service import sslutils
|
|
||||||
|
|
||||||
|
|
||||||
def register_opts(conf):
|
|
||||||
sslutils.register_opts(conf)
|
|
||||||
|
|
||||||
|
|
||||||
def list_opts():
|
|
||||||
# The oslo_cache library returns a list of tuples
|
|
||||||
return dict(sslutils.list_opts())
|
|
@@ -31,9 +31,9 @@ from cursive import signature_utils
|
|||||||
import glanceclient
|
import glanceclient
|
||||||
import glanceclient.exc
|
import glanceclient.exc
|
||||||
from glanceclient.v2 import schemas
|
from glanceclient.v2 import schemas
|
||||||
|
from keystoneauth1 import loading as ks_loading
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
from oslo_service import sslutils
|
|
||||||
from oslo_utils import excutils
|
from oslo_utils import excutils
|
||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
import six
|
import six
|
||||||
@@ -50,6 +50,24 @@ from nova.objects import fields
|
|||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
CONF = nova.conf.CONF
|
CONF = nova.conf.CONF
|
||||||
|
|
||||||
|
_SESSION = None
|
||||||
|
|
||||||
|
|
||||||
|
def _glanceclient_from_endpoint(context, endpoint, version):
|
||||||
|
global _SESSION
|
||||||
|
|
||||||
|
if not _SESSION:
|
||||||
|
_SESSION = ks_loading.load_session_from_conf_options(
|
||||||
|
CONF, nova.conf.glance.glance_group.name)
|
||||||
|
|
||||||
|
auth = context.get_auth_plugin()
|
||||||
|
|
||||||
|
# TODO(johngarbutt) eventually we should default to getting the
|
||||||
|
# endpoint URL from the service catalog.
|
||||||
|
return glanceclient.Client(version, session=_SESSION, auth=auth,
|
||||||
|
endpoint_override=endpoint,
|
||||||
|
global_request_id=context.global_id)
|
||||||
|
|
||||||
|
|
||||||
def generate_glance_url():
|
def generate_glance_url():
|
||||||
"""Return a random glance url from the api servers we know about."""
|
"""Return a random glance url from the api servers we know about."""
|
||||||
@@ -85,27 +103,6 @@ def generate_identity_headers(context, status='Confirmed'):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _glanceclient_from_endpoint(context, endpoint, version):
|
|
||||||
"""Instantiate a new glanceclient.Client object."""
|
|
||||||
params = {}
|
|
||||||
# NOTE(sdague): even if we aren't using keystone, it doesn't
|
|
||||||
# hurt to send these headers.
|
|
||||||
params['identity_headers'] = generate_identity_headers(context)
|
|
||||||
params['global_request_id'] = context.global_id
|
|
||||||
if endpoint.startswith('https://'):
|
|
||||||
# https specific params
|
|
||||||
params['insecure'] = CONF.glance.api_insecure
|
|
||||||
params['ssl_compression'] = False
|
|
||||||
sslutils.is_enabled(CONF)
|
|
||||||
if CONF.ssl.cert_file:
|
|
||||||
params['cert_file'] = CONF.ssl.cert_file
|
|
||||||
if CONF.ssl.key_file:
|
|
||||||
params['key_file'] = CONF.ssl.key_file
|
|
||||||
if CONF.ssl.ca_file:
|
|
||||||
params['cacert'] = CONF.ssl.ca_file
|
|
||||||
return glanceclient.Client(str(version), endpoint, **params)
|
|
||||||
|
|
||||||
|
|
||||||
def get_api_servers():
|
def get_api_servers():
|
||||||
"""Shuffle a list of CONF.glance.api_servers and return an iterator
|
"""Shuffle a list of CONF.glance.api_servers and return an iterator
|
||||||
that will cycle through the list, looping around to the beginning
|
that will cycle through the list, looping around to the beginning
|
||||||
|
@@ -22,6 +22,7 @@ from cursive import exception as cursive_exception
|
|||||||
import glanceclient.exc
|
import glanceclient.exc
|
||||||
from glanceclient.v1 import images
|
from glanceclient.v1 import images
|
||||||
import glanceclient.v2.schemas as schemas
|
import glanceclient.v2.schemas as schemas
|
||||||
|
from keystoneauth1 import loading as ks_loading
|
||||||
import mock
|
import mock
|
||||||
import six
|
import six
|
||||||
from six.moves import StringIO
|
from six.moves import StringIO
|
||||||
@@ -340,52 +341,51 @@ class TestGetImageService(test.NoDBTestCase):
|
|||||||
|
|
||||||
|
|
||||||
class TestCreateGlanceClient(test.NoDBTestCase):
|
class TestCreateGlanceClient(test.NoDBTestCase):
|
||||||
|
|
||||||
|
@mock.patch.object(context.RequestContext, 'get_auth_plugin')
|
||||||
|
@mock.patch.object(ks_loading, 'load_session_from_conf_options')
|
||||||
@mock.patch('glanceclient.Client')
|
@mock.patch('glanceclient.Client')
|
||||||
def test_headers_passed_glanceclient(self, init_mock):
|
def test_glanceclient_with_ks_session(self, mock_client, mock_load,
|
||||||
self.flags(auth_strategy='keystone', group='api')
|
mock_get_auth):
|
||||||
auth_token = 'token'
|
session = "fake_session"
|
||||||
ctx = context.RequestContext('fake', 'fake', auth_token=auth_token)
|
mock_load.return_value = session
|
||||||
|
auth = "fake_auth"
|
||||||
|
mock_get_auth.return_value = auth
|
||||||
|
ctx = context.RequestContext('fake', 'fake', global_request_id='reqid')
|
||||||
|
endpoint = "fake_endpoint"
|
||||||
|
mock_client.side_effect = ["a", "b"]
|
||||||
|
|
||||||
expected_endpoint = 'http://host4:9295'
|
# Reset the cache, so we know its empty before we start
|
||||||
expected_params = {
|
glance._SESSION = None
|
||||||
'identity_headers': {
|
|
||||||
'X-Auth-Token': 'token',
|
result1 = glance._glanceclient_from_endpoint(ctx, endpoint, 2)
|
||||||
'X-User-Id': 'fake',
|
result2 = glance._glanceclient_from_endpoint(ctx, endpoint, 2)
|
||||||
'X-Roles': '',
|
|
||||||
'X-Tenant-Id': 'fake',
|
# Ensure that session is only loaded once.
|
||||||
'X-Identity-Status': 'Confirmed',
|
mock_load.assert_called_once_with(glance.CONF, "glance")
|
||||||
},
|
self.assertEqual(session, glance._SESSION)
|
||||||
'global_request_id': mock.ANY
|
# Ensure new client created every time
|
||||||
|
client_call = mock.call(2, auth="fake_auth",
|
||||||
|
endpoint_override=endpoint, session=session,
|
||||||
|
global_request_id='reqid')
|
||||||
|
mock_client.assert_has_calls([client_call, client_call])
|
||||||
|
self.assertEqual("a", result1)
|
||||||
|
self.assertEqual("b", result2)
|
||||||
|
|
||||||
|
def test_generate_identity_headers(self):
|
||||||
|
ctx = context.RequestContext('user', 'tenant',
|
||||||
|
auth_token='token', roles=["a", "b"])
|
||||||
|
|
||||||
|
result = glance.generate_identity_headers(ctx, 'test')
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
'X-Auth-Token': 'token',
|
||||||
|
'X-User-Id': 'user',
|
||||||
|
'X-Tenant-Id': 'tenant',
|
||||||
|
'X-Roles': 'a,b',
|
||||||
|
'X-Identity-Status': 'test',
|
||||||
}
|
}
|
||||||
glance._glanceclient_from_endpoint(ctx, expected_endpoint, 2)
|
self.assertDictEqual(expected, result)
|
||||||
init_mock.assert_called_once_with('2', expected_endpoint,
|
|
||||||
**expected_params)
|
|
||||||
|
|
||||||
# Test the version is properly passed to glanceclient.
|
|
||||||
init_mock.reset_mock()
|
|
||||||
|
|
||||||
expected_endpoint = 'http://host4:9295'
|
|
||||||
expected_params = {
|
|
||||||
'identity_headers': {
|
|
||||||
'X-Auth-Token': 'token',
|
|
||||||
'X-User-Id': 'fake',
|
|
||||||
'X-Roles': '',
|
|
||||||
'X-Tenant-Id': 'fake',
|
|
||||||
'X-Identity-Status': 'Confirmed',
|
|
||||||
},
|
|
||||||
'global_request_id': mock.ANY
|
|
||||||
}
|
|
||||||
glance._glanceclient_from_endpoint(ctx, expected_endpoint, 2)
|
|
||||||
init_mock.assert_called_once_with('2', expected_endpoint,
|
|
||||||
**expected_params)
|
|
||||||
|
|
||||||
# Test that the IPv6 bracketization adapts the endpoint properly.
|
|
||||||
init_mock.reset_mock()
|
|
||||||
|
|
||||||
expected_endpoint = 'http://[host4]:9295'
|
|
||||||
glance._glanceclient_from_endpoint(ctx, expected_endpoint, 2)
|
|
||||||
init_mock.assert_called_once_with('2', expected_endpoint,
|
|
||||||
**expected_params)
|
|
||||||
|
|
||||||
|
|
||||||
class TestGlanceClientWrapperRetries(test.NoDBTestCase):
|
class TestGlanceClientWrapperRetries(test.NoDBTestCase):
|
||||||
@@ -505,23 +505,6 @@ class TestGlanceClientWrapperRetries(test.NoDBTestCase):
|
|||||||
create_client_mock.return_value = client_mock
|
create_client_mock.return_value = client_mock
|
||||||
|
|
||||||
|
|
||||||
class TestGlanceClientWrapper(test.NoDBTestCase):
|
|
||||||
|
|
||||||
@mock.patch('oslo_service.sslutils.is_enabled')
|
|
||||||
@mock.patch('glanceclient.Client')
|
|
||||||
def test_create_glance_client_with_ssl(self, client_mock,
|
|
||||||
ssl_enable_mock):
|
|
||||||
self.flags(ca_file='foo.cert', cert_file='bar.cert',
|
|
||||||
key_file='wut.key', group='ssl')
|
|
||||||
ctxt = mock.MagicMock()
|
|
||||||
glance._glanceclient_from_endpoint(ctxt, 'https://host4:9295', 2)
|
|
||||||
client_mock.assert_called_once_with(
|
|
||||||
'2', 'https://host4:9295', global_request_id=mock.ANY,
|
|
||||||
insecure=False, ssl_compression=False,
|
|
||||||
cert_file='bar.cert', key_file='wut.key', cacert='foo.cert',
|
|
||||||
identity_headers=mock.ANY)
|
|
||||||
|
|
||||||
|
|
||||||
class TestDownloadNoDirectUri(test.NoDBTestCase):
|
class TestDownloadNoDirectUri(test.NoDBTestCase):
|
||||||
|
|
||||||
"""Tests the download method of the GlanceImageServiceV2 when the
|
"""Tests the download method of the GlanceImageServiceV2 when the
|
||||||
|
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
upgrade:
|
||||||
|
- |
|
||||||
|
The ``ssl`` options were only used by Nova code that interacts with
|
||||||
|
Glance client. These options are now defined and read by Keystoneauth.
|
||||||
|
``api_insecure`` option from glance group is renamed to ``insecure``. The
|
||||||
|
following ''ssl'' options are moved to ``glance`` group
|
||||||
|
|
||||||
|
- ``ca_file`` now called ``cafile``
|
||||||
|
- ``cert_file`` now called ``certfile``
|
||||||
|
- ``key_file`` now called ``keyfile``
|
Reference in New Issue
Block a user