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:
Sarafraj Singh 2016-12-19 16:26:45 -06:00 committed by Eric Fried
parent 3d84232d7b
commit b277b10df6
6 changed files with 92 additions and 118 deletions

View File

@ -60,7 +60,6 @@ from nova.conf import service
from nova.conf import service_token
from nova.conf import servicegroup
from nova.conf import spice
from nova.conf import ssl
from nova.conf import upgrade_levels
from nova.conf import vendordata
from nova.conf import vmware
@ -112,7 +111,6 @@ service.register_opts(CONF)
service_token.register_opts(CONF)
servicegroup.register_opts(CONF)
spice.register_opts(CONF)
ssl.register_opts(CONF)
upgrade_levels.register_opts(CONF)
vendordata.register_opts(CONF)
vmware.register_opts(CONF)

View File

@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from keystoneauth1 import loading as ks_loading
from oslo_config import cfg
glance_group = cfg.OptGroup(
@ -34,14 +35,6 @@ Possible values:
* 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").
"""),
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',
default=0,
@ -142,6 +135,23 @@ def register_opts(conf):
conf.register_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():
return {glance_group: glance_opts}
return {
glance_group: (
glance_opts +
ks_loading.get_session_conf_options())
}

View File

@ -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())

View File

@ -31,9 +31,9 @@ from cursive import signature_utils
import glanceclient
import glanceclient.exc
from glanceclient.v2 import schemas
from keystoneauth1 import loading as ks_loading
from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_service import sslutils
from oslo_utils import excutils
from oslo_utils import timeutils
import six
@ -50,6 +50,24 @@ from nova.objects import fields
LOG = logging.getLogger(__name__)
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():
"""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():
"""Shuffle a list of CONF.glance.api_servers and return an iterator
that will cycle through the list, looping around to the beginning

View File

@ -22,6 +22,7 @@ from cursive import exception as cursive_exception
import glanceclient.exc
from glanceclient.v1 import images
import glanceclient.v2.schemas as schemas
from keystoneauth1 import loading as ks_loading
import mock
import six
from six.moves import StringIO
@ -340,52 +341,51 @@ class TestGetImageService(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')
def test_headers_passed_glanceclient(self, init_mock):
self.flags(auth_strategy='keystone', group='api')
auth_token = 'token'
ctx = context.RequestContext('fake', 'fake', auth_token=auth_token)
def test_glanceclient_with_ks_session(self, mock_client, mock_load,
mock_get_auth):
session = "fake_session"
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'
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
# Reset the cache, so we know its empty before we start
glance._SESSION = None
result1 = glance._glanceclient_from_endpoint(ctx, endpoint, 2)
result2 = glance._glanceclient_from_endpoint(ctx, endpoint, 2)
# Ensure that session is only loaded once.
mock_load.assert_called_once_with(glance.CONF, "glance")
self.assertEqual(session, glance._SESSION)
# 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)
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)
self.assertDictEqual(expected, result)
class TestGlanceClientWrapperRetries(test.NoDBTestCase):
@ -505,23 +505,6 @@ class TestGlanceClientWrapperRetries(test.NoDBTestCase):
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):
"""Tests the download method of the GlanceImageServiceV2 when the

View File

@ -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``