Add identity endpoint creation to bootstrap

To enable the bootstrapped admin user to perform identity operations we
must also bootstrap the identity endpoint.

Allow specifying service name, endpoint urls and region information to
the bootstrap command.

Change-Id: Ie78c61ecf1e5f787dd2528b887c1642fd8d457ff
Closes-Bug: #1550057
This commit is contained in:
Jamie Lennox 2016-02-26 12:24:47 +11:00
parent 432f5f2348
commit 64c94e74c9
2 changed files with 203 additions and 0 deletions

View File

@ -63,10 +63,17 @@ class BootStrap(BaseApp):
self.load_backends()
self.project_id = uuid.uuid4().hex
self.role_id = uuid.uuid4().hex
self.service_id = None
self.service_name = None
self.username = None
self.project_name = None
self.role_name = None
self.password = None
self.public_url = None
self.internal_url = None
self.admin_url = None
self.region_id = None
self.endpoints = {}
@classmethod
def add_argument_parser(cls, subparsers):
@ -88,6 +95,31 @@ class BootStrap(BaseApp):
metavar='OS_BOOTSTRAP_ROLE_NAME',
help=('The initial role-name created during the '
'keystone bootstrap process.'))
parser.add_argument('--bootstrap-service-name', default='keystone',
metavar='OS_BOOTSTRAP_SERVICE_NAME',
help=('The initial name for the initial identity '
'service created during the keystone '
'bootstrap process.'))
parser.add_argument('--bootstrap-admin-url',
metavar='OS_BOOTSTRAP_ADMIN_URL',
help=('The initial identity admin url created '
'during the keystone bootstrap process. '
'e.g. http://127.0.0.1:35357/v2.0'))
parser.add_argument('--bootstrap-public-url',
metavar='OS_BOOTSTRAP_PUBLIC_URL',
help=('The initial identity public url created '
'during the keystone bootstrap process. '
'e.g. http://127.0.0.1:5000/v2.0'))
parser.add_argument('--bootstrap-internal-url',
metavar='OS_BOOTSTRAP_INTERNAL_URL',
help=('The initial identity internal url created '
'during the keystone bootstrap process. '
'e.g. http://127.0.0.1:5000/v2.0'))
parser.add_argument('--bootstrap-region-id',
metavar='OS_BOOTSTRAP_REGION_ID',
help=('The initial region_id endpoints will be '
'placed in during the keystone bootstrap '
'process.'))
return parser
def load_backends(self):
@ -95,6 +127,7 @@ class BootStrap(BaseApp):
self.resource_manager = drivers['resource_api']
self.identity_manager = drivers['identity_api']
self.assignment_manager = drivers['assignment_api']
self.catalog_manager = drivers['catalog_api']
self.role_manager = drivers['role_api']
def _get_config(self):
@ -110,6 +143,21 @@ class BootStrap(BaseApp):
self.password = (
os.environ.get('OS_BOOTSTRAP_PASSWORD') or
CONF.command.bootstrap_password)
self.service_name = (
os.environ.get('OS_BOOTSTRAP_SERVICE_NAME') or
CONF.command.bootstrap_service_name)
self.admin_url = (
os.environ.get('OS_BOOTSTRAP_ADMIN_URL') or
CONF.command.bootstrap_admin_url)
self.public_url = (
os.environ.get('OS_BOOTSTRAP_PUBLIC_URL') or
CONF.command.bootstrap_public_url)
self.internal_url = (
os.environ.get('OS_BOOTSTRAP_INTERNAL_URL') or
CONF.command.bootstrap_internal_url)
self.region_id = (
os.environ.get('OS_BOOTSTRAP_REGION_ID') or
CONF.command.bootstrap_region_id)
def do_bootstrap(self):
"""Perform the bootstrap actions.
@ -215,6 +263,80 @@ class BootStrap(BaseApp):
'role': self.role_name,
'project': self.project_name})
if self.region_id:
try:
self.catalog_manager.create_region(
region_ref={'id': self.region_id}
)
LOG.info(_LI('Created Region %s'), self.region_id)
except exception.Conflict:
LOG.info(_LI('Region %s exists, skipping creation.'),
self.region_id)
if self.public_url or self.admin_url or self.internal_url:
hints = driver_hints.Hints()
hints.add_filter('type', 'identity')
services = self.catalog_manager.list_services(hints)
if services:
service_ref = services[0]
hints = driver_hints.Hints()
hints.add_filter('service_id', service_ref['id'])
if self.region_id:
hints.add_filter('region_id', self.region_id)
endpoints = self.catalog_manager.list_endpoints(hints)
else:
service_ref = {'id': uuid.uuid4().hex,
'name': self.service_name,
'type': 'identity',
'enabled': True}
self.catalog_manager.create_service(
service_id=service_ref['id'],
service_ref=service_ref)
endpoints = []
self.service_id = service_ref['id']
available_interfaces = {e['interface']: e for e in endpoints}
expected_endpoints = {'public': self.public_url,
'internal': self.internal_url,
'admin': self.admin_url}
for interface, url in expected_endpoints.items():
if not url:
# not specified to bootstrap command
continue
try:
endpoint_ref = available_interfaces[interface]
except KeyError:
endpoint_ref = {'id': uuid.uuid4().hex,
'interface': interface,
'url': url,
'service_id': self.service_id,
'enabled': True}
if self.region_id:
endpoint_ref['region_id'] = self.region_id
self.catalog_manager.create_endpoint(
endpoint_id=endpoint_ref['id'],
endpoint_ref=endpoint_ref)
LOG.info(_LI('Created %(interface)s endpoint %(url)s'),
{'interface': interface, 'url': url})
else:
# NOTE(jamielennox): electing not to update existing
# endpoints here. There may be call to do so in future.
LOG.info(_LI('Skipping %s endpoint as already created'),
interface)
self.endpoints[interface] = endpoint_ref['id']
@classmethod
def main(cls):
klass = cls()

View File

@ -87,6 +87,30 @@ class CliBootStrapTestCase(unit.SQLDriverOverrides, unit.TestCase):
user['id'],
bootstrap.password)
if bootstrap.region_id:
region = bootstrap.catalog_manager.get_region(bootstrap.region_id)
self.assertEqual(self.region_id, region['id'])
if bootstrap.service_id:
svc = bootstrap.catalog_manager.get_service(bootstrap.service_id)
self.assertEqual(self.service_name, svc['name'])
self.assertEqual(set(['admin', 'public', 'internal']),
set(bootstrap.endpoints))
urls = {'public': self.public_url,
'internal': self.internal_url,
'admin': self.admin_url}
for interface, url in urls.items():
endpoint_id = bootstrap.endpoints[interface]
endpoint = bootstrap.catalog_manager.get_endpoint(endpoint_id)
self.assertEqual(self.region_id, endpoint['region_id'])
self.assertEqual(url, endpoint['url'])
self.assertEqual(svc['id'], endpoint['service_id'])
self.assertEqual(interface, endpoint['interface'])
def test_bootstrap_is_idempotent(self):
# NOTE(morganfainberg): Ensure we can run bootstrap multiple times
# without erroring.
@ -107,6 +131,11 @@ class CliBootStrapTestCaseWithEnvironment(CliBootStrapTestCase):
self.username = uuid.uuid4().hex
self.project_name = uuid.uuid4().hex
self.role_name = uuid.uuid4().hex
self.service_name = uuid.uuid4().hex
self.public_url = uuid.uuid4().hex
self.internal_url = uuid.uuid4().hex
self.admin_url = uuid.uuid4().hex
self.region_id = uuid.uuid4().hex
self.default_domain = {
'id': CONF.identity.default_domain_id,
'name': 'Default',
@ -123,6 +152,21 @@ class CliBootStrapTestCaseWithEnvironment(CliBootStrapTestCase):
self.useFixture(
fixtures.EnvironmentVariable('OS_BOOTSTRAP_ROLE_NAME',
newvalue=self.role_name))
self.useFixture(
fixtures.EnvironmentVariable('OS_BOOTSTRAP_SERVICE_NAME',
newvalue=self.service_name))
self.useFixture(
fixtures.EnvironmentVariable('OS_BOOTSTRAP_PUBLIC_URL',
newvalue=self.public_url))
self.useFixture(
fixtures.EnvironmentVariable('OS_BOOTSTRAP_INTERNAL_URL',
newvalue=self.internal_url))
self.useFixture(
fixtures.EnvironmentVariable('OS_BOOTSTRAP_ADMIN_URL',
newvalue=self.admin_url))
self.useFixture(
fixtures.EnvironmentVariable('OS_BOOTSTRAP_REGION_ID',
newvalue=self.region_id))
def test_assignment_created_with_user_exists(self):
# test assignment can be created if user already exists.
@ -155,6 +199,43 @@ class CliBootStrapTestCaseWithEnvironment(CliBootStrapTestCase):
bootstrap.role_manager.create_role(role['id'], role)
self._do_test_bootstrap(bootstrap)
def test_assignment_created_with_region_exists(self):
# test assignment can be created if role already exists.
bootstrap = cli.BootStrap()
bootstrap.resource_manager.create_domain(self.default_domain['id'],
self.default_domain)
region = unit.new_region_ref(id=self.region_id)
bootstrap.catalog_manager.create_region(region)
self._do_test_bootstrap(bootstrap)
def test_endpoints_created_with_service_exists(self):
# test assignment can be created if role already exists.
bootstrap = cli.BootStrap()
bootstrap.resource_manager.create_domain(self.default_domain['id'],
self.default_domain)
service = unit.new_service_ref(name=self.service_name)
bootstrap.catalog_manager.create_service(service['id'], service)
self._do_test_bootstrap(bootstrap)
def test_endpoints_created_with_endpoint_exists(self):
# test assignment can be created if role already exists.
bootstrap = cli.BootStrap()
bootstrap.resource_manager.create_domain(self.default_domain['id'],
self.default_domain)
service = unit.new_service_ref(name=self.service_name)
bootstrap.catalog_manager.create_service(service['id'], service)
region = unit.new_region_ref(id=self.region_id)
bootstrap.catalog_manager.create_region(region)
endpoint = unit.new_endpoint_ref(interface='public',
service_id=service['id'],
url=self.public_url,
region_id=self.region_id)
bootstrap.catalog_manager.create_endpoint(endpoint['id'], endpoint)
self._do_test_bootstrap(bootstrap)
class CliDomainConfigAllTestCase(unit.SQLDriverOverrides, unit.TestCase):