Add --os-endpoint-type cli optional argument

User should be able to specify the endpoint type through
a CLI optional argument/ENV variable setting. We will name this new
optional argument: --os-endpoint-type (Env: OS_ENDPOINT_TYPE) and
based on the value given, the service API will use that specific
endpoint type. Possible values: public, admin, internal.

DocImpact
Closes-Bug: #1454392
Change-Id: Ife3d4e46b44c0ddcd712b1130e27e362545a9a29
This commit is contained in:
Roxana Gherle 2015-05-22 16:22:35 -07:00
parent 7e067c6f4f
commit 5521e4c504
15 changed files with 97 additions and 5 deletions

View File

@ -78,6 +78,7 @@ The keys match the :program:`openstack` global options but without the
username: openstack
password: xyzpdq!lazydog
region_name: DFW,ORD,IAD
endpoint_type: internal
In the above example, the ``auth_url`` for the ``rackspace`` cloud is taken
from :file:`clouds-public.yaml` (see below).
@ -96,6 +97,7 @@ to the following options if the ``rackspace`` entry in :file:`clouds-public.yaml
--os-username openstack
--os-password xyzpdq!lazydog
--os-region-name DFW
--os-endpoint-type internal
and can be selected on the command line::
@ -105,13 +107,17 @@ Note that multiple regions are listed in the ``rackspace`` entry. An otherwise
identical configuration is created for each region. If ``-os-region-name`` is not
specified on the command line, the first region in the list is used by default.
The selection of ``endpoint_type`` (as seen above in the ``rackspace`` entry)
is optional. For this configuration to work, every service for this cloud
instance must already be configured to support this type of endpoint.
clouds-public.yaml
~~~~~~~~~~~~~~~~~~
:file:`clouds-public.yaml` is a configuration file that is intended to contain
public information about clouds that are common across a large number of users.
The idea is that :file:`clouds-public.yaml` could easily be shared among users
to simplify public could configuration.
to simplify public cloud configuration.
Similar to :file:`clouds.yaml`, OpenStackClient looks for
:file:`clouds-public.yaml` in the following locations:

View File

@ -120,6 +120,8 @@ OPTIONS
:option:`--os-XXXX-api-version` <XXXX-api-version>
Additional API version options will be available depending on the installed API libraries.
:option:`--os-endpoint-type` <endpoint-type>
Endpoint type. Valid options are `public`, `admin` and `internal`.
COMMANDS
========
@ -344,6 +346,9 @@ The following environment variables can be set to alter the behaviour of :progra
:envvar:`OS_XXXX_API_VERSION`
Additional API version options will be available depending on the installed API libraries.
:envvar:`OS_ENDPOINT_TYPE`
Endpoint type. Valid options are `public`, `admin` and `internal`.
BUGS
====

View File

@ -86,6 +86,7 @@ class ClientManager(object):
self._pw_callback = pw_func
self._url = self._cli_options.auth.get('url', None)
self._region_name = self._cli_options.region_name
self._endpoint_type = self._cli_options.endpoint_type
self.timing = self._cli_options.timing
@ -181,18 +182,23 @@ class ClientManager(object):
self._auth_ref = self.auth.get_auth_ref(self.session)
return self._auth_ref
def get_endpoint_for_service_type(self, service_type, region_name=None):
def get_endpoint_for_service_type(self, service_type, region_name=None,
endpoint_type='public'):
"""Return the endpoint URL for the service type."""
if not endpoint_type:
endpoint_type = 'public'
# See if we are using password flow auth, i.e. we have a
# service catalog to select endpoints from
if self.auth_ref:
endpoint = self.auth_ref.service_catalog.url_for(
service_type=service_type,
region_name=region_name,
endpoint_type=endpoint_type,
)
else:
# Get the passed endpoint directly from the auth plugin
endpoint = self.auth.get_endpoint(self.session)
endpoint = self.auth.get_endpoint(self.session,
interface=endpoint_type)
return endpoint

View File

@ -368,3 +368,11 @@ def read_blob_file_contents(blob_file):
except IOError:
msg = "Error occurred trying to read from file %s"
raise exceptions.CommandError(msg % blob_file)
def build_kwargs_dict(arg_name, value):
"""Return a dictionary containing `arg_name` if `value` is set."""
kwargs = {}
if value:
kwargs[arg_name] = value
return kwargs

View File

@ -48,12 +48,17 @@ def make_client(instance):
extensions = [extension.Extension('list_extensions', list_extensions)]
# Remember endpoint_type only if it is set
kwargs = utils.build_kwargs_dict('endpoint_type',
instance._endpoint_type)
client = compute_client(
session=instance.session,
extensions=extensions,
http_log_debug=http_log_debug,
timings=instance.timing,
region_name=instance._region_name,
**kwargs
)
return client

View File

@ -46,10 +46,15 @@ def make_client(instance):
API_VERSIONS)
LOG.debug('Instantiating identity client: %s', identity_client)
# Remember interface only if endpoint_type is set
kwargs = utils.build_kwargs_dict('interface',
instance._endpoint_type)
client = identity_client(
session=instance.session,
region_name=instance._region_name,
)
**kwargs
)
return client

View File

@ -46,6 +46,7 @@ def make_client(instance):
endpoint = instance.get_endpoint_for_service_type(
API_NAME,
region_name=instance._region_name,
endpoint_type=instance._endpoint_type,
)
client = image_client(
@ -68,6 +69,7 @@ def make_client(instance):
endpoint=instance.get_endpoint_for_service_type(
IMAGE_API_TYPE,
region_name=instance._region_name,
endpoint_type=instance._endpoint_type,
)
)

View File

@ -47,11 +47,17 @@ def make_client(instance):
endpoint = instance.get_endpoint_for_service_type(
API_NAME,
region_name=instance._region_name,
endpoint_type=instance._endpoint_type,
)
# Remember endpoint_type only if it is set
kwargs = utils.build_kwargs_dict('endpoint_type',
instance._endpoint_type)
client = network_client(
session=instance.session,
region_name=instance._region_name,
**kwargs
)
network_api = utils.get_client_class(

View File

@ -36,6 +36,7 @@ def make_client(instance):
endpoint = instance.get_endpoint_for_service_type(
'object-store',
region_name=instance._region_name,
endpoint_type=instance._endpoint_type,
)
client = object_store_v1.APIv1(

View File

@ -208,6 +208,15 @@ class OpenStackShell(app.App):
help='Default domain ID, default=' +
DEFAULT_DOMAIN +
' (Env: OS_DEFAULT_DOMAIN)')
parser.add_argument(
'--os-endpoint-type',
metavar='<endpoint-type>',
dest='endpoint_type',
choices=['admin', 'public', 'internal'],
default=utils.env('OS_ENDPOINT_TYPE'),
help='Select an endpoint type.'
' Valid endpoint types: [admin, public, internal].'
' (Env: OS_ENDPOINT_TYPE)')
parser.add_argument(
'--timing',
default=False,
@ -254,7 +263,10 @@ class OpenStackShell(app.App):
self.options.project_name = tenant_name
# Do configuration file handling
cc = cloud_config.OpenStackConfig()
# Ignore the default value of endpoint_type. Only if it is set later
# will it be used.
cc = cloud_config.OpenStackConfig(
override_defaults={'endpoint_type': None, })
self.log.debug("defaults: %s", cc.defaults)
self.cloud = cc.get_one_cloud(

View File

@ -54,6 +54,7 @@ class FakeOptions(object):
self.identity_api_version = '2.0'
self.timing = None
self.region_name = None
self.endpoint_type = None
self.url = None
self.auth = {}
self.default_domain = 'default'
@ -123,6 +124,8 @@ class TestClientManager(utils.TestCase):
auth_url=fakes.AUTH_URL,
),
auth_type='v2token',
endpoint_type=fakes.ENDPOINT_TYPE,
region_name=fakes.REGION_NAME,
),
api_version=API_VERSION,
verify=True
@ -137,6 +140,14 @@ class TestClientManager(utils.TestCase):
client_manager.auth,
auth_v2.Token,
)
self.assertEqual(
fakes.ENDPOINT_TYPE,
client_manager._endpoint_type,
)
self.assertEqual(
fakes.REGION_NAME,
client_manager._region_name,
)
self.assertFalse(client_manager._insecure)
self.assertTrue(client_manager._verify)

View File

@ -159,6 +159,16 @@ class TestUtils(test_utils.TestCase):
self.assertFalse(utils.wait_for_delete(manager, res_id))
self.assertFalse(mock_sleep.called)
def test_build_kwargs_dict_value_set(self):
self.assertEqual({'arg_bla': 'bla'},
utils.build_kwargs_dict('arg_bla', 'bla'))
def test_build_kwargs_dict_value_None(self):
self.assertEqual({}, utils.build_kwargs_dict('arg_bla', None))
def test_build_kwargs_dict_value_empty_str(self):
self.assertEqual({}, utils.build_kwargs_dict('arg_bla', ''))
class NoUniqueMatch(Exception):
pass

View File

@ -26,6 +26,8 @@ AUTH_URL = "http://0.0.0.0"
USERNAME = "itchy"
PASSWORD = "scratchy"
PROJECT_NAME = "poochie"
REGION_NAME = "richie"
ENDPOINT_TYPE = "catchy"
TEST_RESPONSE_DICT = fixture.V2Token(token_id=AUTH_TOKEN,
user_name=USERNAME)

View File

@ -38,6 +38,7 @@ DEFAULT_REGION_NAME = "ZZ9_Plural_Z_Alpha"
DEFAULT_TOKEN = "token"
DEFAULT_SERVICE_URL = "http://127.0.0.1:8771/v3.0/"
DEFAULT_AUTH_PLUGIN = "v2password"
DEFAULT_ENDPOINT_TYPE = "internal"
DEFAULT_COMPUTE_API_VERSION = "2"
DEFAULT_IDENTITY_API_VERSION = "2"
@ -61,6 +62,7 @@ CLOUD_1 = {
},
'region_name': 'occ-cloud',
'donut': 'glazed',
'endpoint_type': 'public',
}
}
}
@ -104,6 +106,7 @@ global_options = {
'--os-default-domain': (DEFAULT_DOMAIN_NAME, True, True),
'--os-cacert': ('/dev/null', True, True),
'--timing': (True, True, False),
'--os-endpoint-type': (DEFAULT_ENDPOINT_TYPE, True, True)
}
auth_options = {
@ -123,6 +126,7 @@ auth_options = {
'--os-auth-type': ("v2password", True, True),
'--os-token': (DEFAULT_TOKEN, True, True),
'--os-url': (DEFAULT_SERVICE_URL, True, True),
'--os-endpoint-type': (DEFAULT_ENDPOINT_TYPE, True, True),
}
@ -608,6 +612,10 @@ class TestShellCli(TestShell):
'glazed',
_shell.cloud.config['donut'],
)
self.assertEqual(
'public',
_shell.cloud.config['endpoint_type'],
)
@mock.patch("os_client_config.config.OpenStackConfig._load_vendor_file")
@mock.patch("os_client_config.config.OpenStackConfig._load_config_file")

View File

@ -53,11 +53,16 @@ def make_client(instance):
extensions = [extension.Extension('list_extensions', list_extensions)]
# Remember endpoint_type only if it is set
kwargs = utils.build_kwargs_dict('endpoint_type',
instance._endpoint_type)
client = volume_client(
session=instance.session,
extensions=extensions,
http_log_debug=http_log_debug,
region_name=instance._region_name,
**kwargs
)
return client