Add support for PROJECT_DOMAIN_ID, USER_DOMAIN_ID.
Currently in kingbird-client there is NO support for PROJECT_DOMAIN_NAME/USER_DOMAIN_NAME OR PROJECT_DOMAIN_ID/USER_DOMAIN_ID but in the latest release of OpenStack, there are options for the above-mentioned environment variables. Added tests for the same and made README.rst better. Closes-Bug: #1716364 Change-Id: I09625acafc0e3d43fd6008d3de930e98195d14f3
This commit is contained in:
parent
bf641ae368
commit
3c6a972c86
51
README.rst
51
README.rst
|
@ -1,11 +1,21 @@
|
|||
Kingbird
|
||||
=========
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/python-kingbirdclient.svg
|
||||
:target: https://pypi.python.org/pypi/python-kingbirdclient/
|
||||
:alt: Latest Version
|
||||
|
||||
.. image:: https://img.shields.io/pypi/dm/python-kingbirdclient.svg
|
||||
:target: https://pypi.python.org/pypi/python-kingbirdclient/
|
||||
:alt: Downloads
|
||||
|
||||
Centralised service for multi-region OpenStack deployments.
|
||||
|
||||
Kingbird is an centralized OpenStack service that provides resource operation and
|
||||
management across multiple OpenStack instances in a multi-region OpenStack deployment.
|
||||
This service is part of the OPNFV Multisite project that intends to address
|
||||
the use cases related to distributed cloud environments.
|
||||
|
||||
Kingbird provides features like centralized quota management, centralized view for
|
||||
distributed virtual resources, global view for tenant level IP/MAC address space management,
|
||||
synchronisation of ssh keys, images, flavors, etc. across regions.
|
||||
|
@ -23,16 +33,16 @@ provides a Python API (the ``kingbirdclient`` module) and a command-line tool
|
|||
Installation
|
||||
------------
|
||||
|
||||
First of all, clone the repo and go to the repo directory:
|
||||
First of all, clone the repo and go to the repo directory::
|
||||
|
||||
$ git clone https://github.com/openstack/python-kingbirdclient.git
|
||||
$ cd python-kingbirdclient
|
||||
|
||||
Then just run:
|
||||
Then just run::
|
||||
|
||||
$ pip install -e .
|
||||
|
||||
or
|
||||
or::
|
||||
|
||||
$ pip install -r requirements.txt
|
||||
$ python setup.py install
|
||||
|
@ -41,25 +51,32 @@ Running Kingbird client
|
|||
-----------------------
|
||||
|
||||
If Kingbird authentication is enabled, provide the information about OpenStack
|
||||
auth to environment variables. Type:
|
||||
auth to environment variables. Type::
|
||||
|
||||
$ export OS_PROJECT_DOMAIN_ID=default
|
||||
$ export OS_REGION_NAME=RegionOne
|
||||
$ export OS_USER_DOMAIN_ID=default
|
||||
$ export OS_PROJECT_NAME=<project_name>
|
||||
$ export OS_IDENTITY_API_VERSION=<identity_version>
|
||||
$ export OS_PASSWORD=<password>
|
||||
$ export OS_AUTH_TYPE=password
|
||||
$ export OS_AUTH_URL=http://<Keystone_host>/identity
|
||||
$ export OS_USERNAME=<user_name>
|
||||
$ export OS_TENANT_NAME=<tenant_name>
|
||||
$ export OS_VOLUME_API_VERSION=<volume_version>
|
||||
$ export OS_PROJECT_DOMAIN_ID=<PROJECT_DOMAIN_ID>
|
||||
$ export OS_REGION_NAME=<Region>
|
||||
$ export OS_USER_DOMAIN_ID=<USER_DOMAIN_ID>
|
||||
$ export OS_PROJECT_NAME=<project_name>
|
||||
$ export OS_IDENTITY_API_VERSION=<identity_version>
|
||||
$ export OS_PASSWORD=<password>
|
||||
$ export OS_AUTH_TYPE=<auth_type>
|
||||
$ export OS_AUTH_URL=http://<Keystone_host>/identity
|
||||
$ export OS_USERNAME=<user_name>
|
||||
$ export OS_TENANT_NAME=<tenant_name>
|
||||
|
||||
To make sure Kingbird client works, type:
|
||||
.. note:: In client, we use Keystone auth version v3 as
|
||||
server supports only v3.*
|
||||
|
||||
To make sure Kingbird client works, type::
|
||||
|
||||
$ kingbird quota defaults
|
||||
|
||||
You can see the list of available commands typing:
|
||||
or::
|
||||
|
||||
$ kingbird sync list
|
||||
|
||||
|
||||
You can see the list of available commands typing::
|
||||
|
||||
$ kingbird --help
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ def client(kingbird_url=None, username=None, api_key=None,
|
|||
endpoint_type='publicURL', service_type='synchronization',
|
||||
auth_token=None, user_id=None, cacert=None, insecure=False,
|
||||
profile=None, auth_type='keystone', client_id=None,
|
||||
client_secret=None):
|
||||
client_secret=None, **kwargs):
|
||||
if kingbird_url and not isinstance(kingbird_url, six.string_types):
|
||||
raise RuntimeError('Kingbird url should be a string.')
|
||||
|
||||
|
@ -42,7 +42,8 @@ def client(kingbird_url=None, username=None, api_key=None,
|
|||
profile=profile,
|
||||
auth_type=auth_type,
|
||||
client_id=client_id,
|
||||
client_secret=client_secret
|
||||
client_secret=client_secret,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ class Client(object):
|
|||
endpoint_type='publicURL', service_type='synchronization',
|
||||
auth_token=None, user_id=None, cacert=None, insecure=False,
|
||||
profile=None, auth_type='keystone', client_id=None,
|
||||
client_secret=None, session=None):
|
||||
client_secret=None, session=None, **kwargs):
|
||||
"""Kingbird communicates with Keystone to fetch necessary values."""
|
||||
if kingbird_url and not isinstance(kingbird_url, six.string_types):
|
||||
raise RuntimeError('Kingbird url should be a string.')
|
||||
|
@ -59,7 +59,8 @@ class Client(object):
|
|||
user_id,
|
||||
session,
|
||||
cacert,
|
||||
insecure
|
||||
insecure,
|
||||
**kwargs
|
||||
)
|
||||
)
|
||||
else:
|
||||
|
@ -93,7 +94,7 @@ def authenticate(kingbird_url=None, username=None,
|
|||
api_key=None, project_name=None, auth_url=None,
|
||||
project_id=None, endpoint_type='publicURL',
|
||||
service_type='synchronization', auth_token=None, user_id=None,
|
||||
session=None, cacert=None, insecure=False):
|
||||
session=None, cacert=None, insecure=False, **kwargs):
|
||||
"""Get token, project_id, user_id and Endpoint."""
|
||||
if project_name and project_id:
|
||||
raise RuntimeError(
|
||||
|
@ -104,6 +105,10 @@ def authenticate(kingbird_url=None, username=None,
|
|||
raise RuntimeError(
|
||||
'Only user name or user id should be set'
|
||||
)
|
||||
user_domain_name = kwargs['user_domain_name']
|
||||
user_domain_id = kwargs['user_domain_id']
|
||||
project_domain_name = kwargs['project_domain_name']
|
||||
project_domain_id = kwargs['project_domain_id']
|
||||
|
||||
if session is None:
|
||||
if auth_token:
|
||||
|
@ -111,7 +116,11 @@ def authenticate(kingbird_url=None, username=None,
|
|||
auth_url=auth_url,
|
||||
token=auth_token,
|
||||
project_id=project_id,
|
||||
project_name=project_name)
|
||||
project_name=project_name,
|
||||
project_domain_name=project_domain_name,
|
||||
project_domain_id=project_domain_id,
|
||||
cacert=cacert,
|
||||
insecure=insecure)
|
||||
|
||||
elif api_key and (username or user_id):
|
||||
auth = auth_plugin.Password(
|
||||
|
@ -120,7 +129,11 @@ def authenticate(kingbird_url=None, username=None,
|
|||
user_id=user_id,
|
||||
password=api_key,
|
||||
project_id=project_id,
|
||||
project_name=project_name)
|
||||
project_name=project_name,
|
||||
user_domain_name=user_domain_name,
|
||||
user_domain_id=user_domain_id,
|
||||
project_domain_name=project_domain_name,
|
||||
project_domain_id=project_domain_id)
|
||||
|
||||
else:
|
||||
raise RuntimeError('You must either provide a valid token or'
|
||||
|
|
|
@ -247,18 +247,38 @@ class KingbirdShell(app.App):
|
|||
'--os-tenant-id',
|
||||
action='store',
|
||||
dest='tenant_id',
|
||||
default=c.env('OS_TENANT_ID'),
|
||||
default=c.env('OS_TENANT_ID', 'OS_PROJECT_ID'),
|
||||
help='Authentication tenant identifier (Env: OS_TENANT_ID)'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--os-project-id',
|
||||
action='store',
|
||||
dest='project_id',
|
||||
default=c.env('OS_TENANT_ID', 'OS_PROJECT_ID'),
|
||||
help='Authentication project identifier (Env: OS_TENANT_ID'
|
||||
' or OS_PROJECT_ID), will use tenant_id if both tenant_id'
|
||||
' and project_id are set'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--os-tenant-name',
|
||||
action='store',
|
||||
dest='tenant_name',
|
||||
default=c.env('OS_TENANT_NAME', 'Default'),
|
||||
default=c.env('OS_TENANT_NAME', 'OS_PROJECT_NAME'),
|
||||
help='Authentication tenant name (Env: OS_TENANT_NAME)'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--os-project-name',
|
||||
action='store',
|
||||
dest='project_name',
|
||||
default=c.env('OS_TENANT_NAME', 'OS_PROJECT_NAME'),
|
||||
help='Authentication project name (Env: OS_TENANT_NAME'
|
||||
' or OS_PROJECT_NAME), will use tenant_name if both'
|
||||
' tenant_name and project_name are set'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--os-auth-token',
|
||||
action='store',
|
||||
|
@ -267,6 +287,42 @@ class KingbirdShell(app.App):
|
|||
help='Authentication token (Env: OS_AUTH_TOKEN)'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--os-project-domain-name',
|
||||
action='store',
|
||||
dest='project_domain_name',
|
||||
default=c.env('OS_PROJECT_DOMAIN_NAME'),
|
||||
help='Authentication project domain name or ID'
|
||||
' (Env: OS_PROJECT_DOMAIN_NAME)'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--os-project-domain-id',
|
||||
action='store',
|
||||
dest='project_domain_id',
|
||||
default=c.env('OS_PROJECT_DOMAIN_ID'),
|
||||
help='Authentication project domain ID'
|
||||
' (Env: OS_PROJECT_DOMAIN_ID)'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--os-user-domain-name',
|
||||
action='store',
|
||||
dest='user_domain_name',
|
||||
default=c.env('OS_USER_DOMAIN_NAME'),
|
||||
help='Authentication user domain name'
|
||||
' (Env: OS_USER_DOMAIN_NAME)'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--os-user-domain-id',
|
||||
action='store',
|
||||
dest='user_domain_id',
|
||||
default=c.env('OS_USER_DOMAIN_ID'),
|
||||
help='Authentication user domain name'
|
||||
' (Env: OS_USER_DOMAIN_ID)'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--os-auth-url',
|
||||
action='store',
|
||||
|
@ -341,11 +397,18 @@ class KingbirdShell(app.App):
|
|||
"via --os-password env[OS_PASSWORD]")
|
||||
)
|
||||
|
||||
kwargs = {
|
||||
'user_domain_name': self.options.user_domain_name,
|
||||
'user_domain_id': self.options.user_domain_id,
|
||||
'project_domain_name': self.options.project_domain_name,
|
||||
'project_domain_id': self.options.project_domain_id
|
||||
}
|
||||
|
||||
self.client = client.client(
|
||||
kingbird_url=self.options.kingbird_url,
|
||||
username=self.options.username,
|
||||
api_key=self.options.password,
|
||||
project_name=self.options.tenant_name,
|
||||
project_name=self.options.tenant_name or self.options.project_name,
|
||||
auth_url=self.options.auth_url,
|
||||
project_id=self.options.tenant_id,
|
||||
endpoint_type=self.options.endpoint_type,
|
||||
|
@ -353,7 +416,8 @@ class KingbirdShell(app.App):
|
|||
auth_token=self.options.token,
|
||||
cacert=self.options.cacert,
|
||||
insecure=self.options.insecure,
|
||||
profile=self.options.profile
|
||||
profile=self.options.profile,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
if not self.options.auth_url and not skip_auth:
|
||||
|
|
|
@ -30,6 +30,10 @@ AUTH_HTTPS_URL = AUTH_HTTP_URL.replace('http', 'https')
|
|||
KINGBIRD_HTTP_URL = 'http://localhost:8118/v1.0'
|
||||
KINGBIRD_HTTPS_URL = KINGBIRD_HTTP_URL.replace('http', 'https')
|
||||
PROFILER_HMAC_KEY = 'SECRET_HMAC_KEY'
|
||||
FAKE_KWARGS = {'user_domain_name': 'fake_user_domain_name',
|
||||
'user_domain_id': 'fake_user_domain_id',
|
||||
'project_domain_name': 'fake_project_domain_name',
|
||||
'project_domain_id': 'fake_project_domain_id'}
|
||||
|
||||
|
||||
class BaseClientTests(testtools.TestCase):
|
||||
|
@ -55,7 +59,8 @@ class BaseClientTests(testtools.TestCase):
|
|||
}
|
||||
|
||||
client.client(username='kingbird', project_name='kingbird',
|
||||
auth_url=AUTH_HTTP_URL, api_key='password')
|
||||
auth_url=AUTH_HTTP_URL, api_key='password',
|
||||
**FAKE_KWARGS)
|
||||
self.assertTrue(mock.called)
|
||||
self.assertEqual(mock.call_args[0], expected_args)
|
||||
self.assertDictEqual(mock.call_args[1], expected_kwargs)
|
||||
|
@ -83,7 +88,8 @@ class BaseClientTests(testtools.TestCase):
|
|||
|
||||
client.client(kingbird_url=KINGBIRD_HTTPS_URL, username='kingbird',
|
||||
project_name='kingbird', auth_url=AUTH_HTTP_URL,
|
||||
api_key='password', cacert=None, insecure=True)
|
||||
api_key='password', cacert=None, insecure=True,
|
||||
**FAKE_KWARGS)
|
||||
|
||||
self.assertTrue(mock.called)
|
||||
self.assertEqual(mock.call_args[0], expected_args)
|
||||
|
@ -118,8 +124,7 @@ class BaseClientTests(testtools.TestCase):
|
|||
auth_url=AUTH_HTTP_URL,
|
||||
api_key='password',
|
||||
cacert=path,
|
||||
insecure=False
|
||||
)
|
||||
insecure=False, **FAKE_KWARGS)
|
||||
finally:
|
||||
os.close(fd)
|
||||
os.unlink(path)
|
||||
|
@ -139,8 +144,7 @@ class BaseClientTests(testtools.TestCase):
|
|||
api_key='password',
|
||||
auth_url=AUTH_HTTP_URL,
|
||||
cacert='/path/to/foobar',
|
||||
insecure=False
|
||||
)
|
||||
insecure=False, **FAKE_KWARGS)
|
||||
|
||||
@mock.patch('logging.Logger.warning')
|
||||
@mock.patch('keystoneauth1.session.Session')
|
||||
|
@ -156,8 +160,8 @@ class BaseClientTests(testtools.TestCase):
|
|||
api_key='password',
|
||||
auth_url=AUTH_HTTP_URL,
|
||||
cacert=path,
|
||||
insecure=True
|
||||
)
|
||||
insecure=True,
|
||||
**FAKE_KWARGS)
|
||||
finally:
|
||||
os.close(fd)
|
||||
os.unlink(path)
|
||||
|
@ -189,8 +193,8 @@ class BaseClientTests(testtools.TestCase):
|
|||
project_name='kingbird',
|
||||
auth_url=AUTH_HTTP_URL,
|
||||
api_key='password',
|
||||
profile=PROFILER_HMAC_KEY
|
||||
)
|
||||
profile=PROFILER_HMAC_KEY,
|
||||
**FAKE_KWARGS)
|
||||
|
||||
self.assertTrue(mock.called)
|
||||
self.assertEqual(mock.call_args[0], expected_args)
|
||||
|
@ -204,18 +208,18 @@ class BaseClientTests(testtools.TestCase):
|
|||
self.assertRaises(RuntimeError, client.client,
|
||||
kingbird_url=KINGBIRD_HTTP_URL,
|
||||
username='kingbird', project_name='kingbird',
|
||||
auth_url=AUTH_HTTP_URL)
|
||||
auth_url=AUTH_HTTP_URL, **FAKE_KWARGS)
|
||||
|
||||
def test_project_name_and_project_id(self):
|
||||
self.assertRaises(RuntimeError, client.client,
|
||||
kingbird_url=KINGBIRD_HTTP_URL,
|
||||
username='kingbird', project_name='kingbird',
|
||||
project_id=str(uuid.uuid4()),
|
||||
auth_url=AUTH_HTTP_URL)
|
||||
auth_url=AUTH_HTTP_URL, **FAKE_KWARGS)
|
||||
|
||||
def test_user_name_and_user_id(self):
|
||||
self.assertRaises(RuntimeError, client.client,
|
||||
kingbird_url=KINGBIRD_HTTP_URL,
|
||||
username='kingbird', project_name='kingbird',
|
||||
user_id=str(uuid.uuid4()),
|
||||
auth_url=AUTH_HTTP_URL)
|
||||
auth_url=AUTH_HTTP_URL, **FAKE_KWARGS)
|
||||
|
|
|
@ -145,3 +145,45 @@ class TestShell(base.BaseShellTests):
|
|||
self.assertTrue(mock.called)
|
||||
params = mock.call_args
|
||||
self.assertEqual(None, params[1]['profile'])
|
||||
|
||||
@mock.patch('kingbirdclient.api.client.client')
|
||||
def test_kingbird_project_name(self, mock):
|
||||
self.shell('--os-project-name default quota defaults')
|
||||
self.assertTrue(mock.called)
|
||||
params = mock.call_args
|
||||
self.assertEqual('default', params[1]['project_name'])
|
||||
|
||||
@mock.patch('kingbirdclient.api.client.client')
|
||||
def test_kingbird_tenant_name(self, mock):
|
||||
self.shell('--os-tenant-name default quota defaults')
|
||||
self.assertTrue(mock.called)
|
||||
params = mock.call_args
|
||||
self.assertEqual('default', params[1]['project_name'])
|
||||
|
||||
@mock.patch('kingbirdclient.api.client.client')
|
||||
def test_kingbird_project_domain_name(self, mock):
|
||||
self.shell('--os-project-domain-name default quota defaults')
|
||||
self.assertTrue(mock.called)
|
||||
params = mock.call_args
|
||||
self.assertEqual('default', params[1]['project_domain_name'])
|
||||
|
||||
@mock.patch('kingbirdclient.api.client.client')
|
||||
def test_kingbird_project_domain_id(self, mock):
|
||||
self.shell('--os-project-domain-id default quota defaults')
|
||||
self.assertTrue(mock.called)
|
||||
params = mock.call_args
|
||||
self.assertEqual('default', params[1]['project_domain_id'])
|
||||
|
||||
@mock.patch('kingbirdclient.api.client.client')
|
||||
def test_kingbird_user_domain_name(self, mock):
|
||||
self.shell('--os-user-domain-name default quota defaults')
|
||||
self.assertTrue(mock.called)
|
||||
params = mock.call_args
|
||||
self.assertEqual('default', params[1]['user_domain_name'])
|
||||
|
||||
@mock.patch('kingbirdclient.api.client.client')
|
||||
def test_kingbird_user_domain_id(self, mock):
|
||||
self.shell('--os-user-domain-id default quota defaults')
|
||||
self.assertTrue(mock.called)
|
||||
params = mock.call_args
|
||||
self.assertEqual('default', params[1]['user_domain_id'])
|
||||
|
|
Loading…
Reference in New Issue