Create trust_id for bay

All bays use the same trustee_user and different trust. A trust is
created for a bay when the bay is created, and is deleted when the
bay is deleted.

Partially-Implements: blueprint registryv2-in-master
Change-Id: Iab2037677f683fe4c562915b98303da02c59c299
This commit is contained in:
Hua Wang 2015-12-01 14:37:47 +08:00
parent 554af35b74
commit 8074f6f4ce
12 changed files with 149 additions and 25 deletions

View File

@ -142,6 +142,10 @@
# (string value) # (string value)
#instance_uuid_format = "[instance: %(uuid)s] " #instance_uuid_format = "[instance: %(uuid)s] "
# Format string for user_identity field of the
# logging_context_format_string (string value)
#logging_user_identity_format = %(user)s %(tenant)s %(domain)s %(user_domain)s %(project_domain)s
# Enables or disables fatal status of deprecations. (boolean value) # Enables or disables fatal status of deprecations. (boolean value)
#fatal_deprecations = false #fatal_deprecations = false
@ -194,6 +198,16 @@
# Shows whether zmq-messaging uses broker or not. (boolean value) # Shows whether zmq-messaging uses broker or not. (boolean value)
#zmq_use_broker = true #zmq_use_broker = true
# Minimal port number for random ports range. (integer value)
#rpc_zmq_min_port = 49152
# Maximal port number for random ports range. (integer value)
#rpc_zmq_max_port = 65536
# Number of retries to find free port number before fail with
# ZMQBindError. (integer value)
#rpc_zmq_bind_port_retries = 100
# Host to locate redis. (string value) # Host to locate redis. (string value)
#host = 127.0.0.1 #host = 127.0.0.1
@ -211,6 +225,11 @@
# messaging, messagingv2, routing, log, test, noop (multi valued) # messaging, messagingv2, routing, log, test, noop (multi valued)
#notification_driver = #notification_driver =
# A URL representing the messaging driver to use for notifications. If
# not set, we fall back to the same configuration used for RPC.
# (string value)
#notification_transport_url = <None>
# AMQP topic used for OpenStack notifications. (list value) # AMQP topic used for OpenStack notifications. (list value)
# Deprecated group/name - [rpc_notifier2]/topics # Deprecated group/name - [rpc_notifier2]/topics
#notification_topics = notifications #notification_topics = notifications
@ -259,7 +278,7 @@
# Specify a timeout after which a gracefully shutdown server will # Specify a timeout after which a gracefully shutdown server will
# exit. Zero value means endless wait. (integer value) # exit. Zero value means endless wait. (integer value)
#graceful_shutdown_timeout = 0 #graceful_shutdown_timeout = 60
[api] [api]
@ -320,7 +339,7 @@
# Location of template to build a swarm cluster on atomic. (string # Location of template to build a swarm cluster on atomic. (string
# value) # value)
#swarm_atomic_template_path = $pybasedir/templates/swarm/swarm.yaml #swarm_atomic_template_path = $pybasedir/templates/swarm/swarmcluster.yaml
# Location of template to build a Mesos cluster on Ubuntu. (string # Location of template to build a Mesos cluster on Ubuntu. (string
# value) # value)
@ -363,23 +382,23 @@
# network drivers include flannel. (list value) # network drivers include flannel. (list value)
#kubernetes_allowed_network_drivers = all #kubernetes_allowed_network_drivers = all
# Default network driver for kubernetes baymodels. # Default network driver for kubernetes baymodels. (string value)
#kubernetes_default_network_driver = flannel #kubernetes_default_network_driver = flannel
# Allowed network drivers for docker swarm baymodels. Use 'all' keyword # Allowed network drivers for docker swarm baymodels. Use 'all'
# to allow all drivers supported for swarm baymodels. Supported # keyword to allow all drivers supported for swarm baymodels.
# network drivers include docker. (list value) # Supported network drivers include docker and flannel. (list value)
#swarm_allowed_network_drivers = all #swarm_allowed_network_drivers = all
# Default network driver for docker swarm baymodels. # Default network driver for docker swarm baymodels. (string value)
#swarm_default_network_driver = docker #swarm_default_network_driver = docker
# Allowed network drivers for mesos baymodels. Use 'all' keyword # Allowed network drivers for mesos baymodels. Use 'all' keyword to
# to allow all drivers supported for mesos baymodels. Supported # allow all drivers supported for mesos baymodels. Supported network
# network drivers include docker. (list value) # drivers include docker. (list value)
#mesos_allowed_network_drivers = all #mesos_allowed_network_drivers = all
# Default network driver for mesos baymodels. # Default network driver for mesos baymodels. (string value)
#mesos_default_network_driver = docker #mesos_default_network_driver = docker
@ -418,7 +437,7 @@
# #
# Indicate whether this resource may be shared with the domain # Indicate whether this resource may be shared with the domain
# received in the requests "origin" header. (string value) # received in the requests "origin" header. (list value)
#allowed_origin = <None> #allowed_origin = <None>
# Indicate that the actual request can include user credentials # Indicate that the actual request can include user credentials
@ -448,7 +467,7 @@
# #
# Indicate whether this resource may be shared with the domain # Indicate whether this resource may be shared with the domain
# received in the requests "origin" header. (string value) # received in the requests "origin" header. (list value)
#allowed_origin = <None> #allowed_origin = <None>
# Indicate that the actual request can include user credentials # Indicate that the actual request can include user credentials
@ -596,7 +615,7 @@
# Default timeout in seconds for docker client operations. (integer # Default timeout in seconds for docker client operations. (integer
# value) # value)
#default_timeout = 10 #default_timeout = 60
# If set, ignore any SSL validation issues (boolean value) # If set, ignore any SSL validation issues (boolean value)
#api_insecure = false #api_insecure = false
@ -614,6 +633,20 @@
#key_file = <None> #key_file = <None>
[docker_registry]
#
# From magnum
#
# User id of the trustee (string value)
#trustee_user_id = <None>
# The roles which are delegated to the trustee by the trustor. (list
# value)
#trust_roles = registry_user
[glance_client] [glance_client]
# #
@ -829,6 +862,14 @@
# Service tenant name. (string value) # Service tenant name. (string value)
#admin_tenant_name = admin #admin_tenant_name = admin
# Authentication type to load (unknown value)
# Deprecated group/name - [DEFAULT]/auth_plugin
#auth_type = <None>
# Config Section from which to load plugin specific options (unknown
# value)
#auth_section = <None>
[magnum_client] [magnum_client]

View File

@ -41,7 +41,8 @@ class BayPatchType(types.JsonPatchType):
def internal_attrs(): def internal_attrs():
internal_attrs = ['/api_address', '/node_addresses', internal_attrs = ['/api_address', '/node_addresses',
'/master_addresses', '/stack_id', '/master_addresses', '/stack_id',
'/ca_cert_ref', '/magnum_cert_ref'] '/ca_cert_ref', '/magnum_cert_ref',
'/registry_trust_id']
return types.JsonPatchType.internal_attrs() + internal_attrs return types.JsonPatchType.internal_attrs() + internal_attrs

View File

@ -540,3 +540,11 @@ class FlavorNotFound(ResourceNotFound):
class NetworkNotFound(ResourceNotFound): class NetworkNotFound(ResourceNotFound):
message = _("Unable to find network %(network)s.") message = _("Unable to find network %(network)s.")
class TrustCreateFailed(MagnumException):
message = _("Failed to create trust for trustee %(trustee_user_id)s.")
class TrustDeleteFailed(MagnumException):
message = _("Failed to delete trust %(trust_id)s.")

View File

@ -83,7 +83,8 @@ class KeystoneClientV3(object):
return 'token' in auth_token_info return 'token' in auth_token_info
def _get_ks_client(self): def _get_ks_client(self):
kwargs = {'auth_url': self.auth_url} kwargs = {'auth_url': self.auth_url,
'endpoint': self.auth_url}
if self.context.trust_id: if self.context.trust_id:
kwargs.update(self._get_admin_credentials()) kwargs.update(self._get_admin_credentials())
kwargs['trust_id'] = self.context.trust_id kwargs['trust_id'] = self.context.trust_id
@ -112,11 +113,17 @@ class KeystoneClientV3(object):
def create_trust(self, trustee_user, role_names, impersonation=True): def create_trust(self, trustee_user, role_names, impersonation=True):
trustor_user_id = self.client.auth_ref.user_id trustor_user_id = self.client.auth_ref.user_id
trustor_project_id = self.client.auth_ref.project_id trustor_project_id = self.client.auth_ref.project_id
trust = self.client.trusts.create(trustor_user=trustor_user_id, try:
project=trustor_project_id, trust = self.client.trusts.create(
trustee_user=trustee_user, trustor_user=trustor_user_id,
impersonation=impersonation, project=trustor_project_id,
role_names=role_names) trustee_user=trustee_user,
impersonation=impersonation,
role_names=role_names)
except Exception as e:
LOG.exception(str(e))
raise exception.TrustCreateFailed(
trustee_user_id=trustee_user)
return trust return trust
def create_trust_to_admin(self, role_names, impersonation=True): def create_trust_to_admin(self, role_names, impersonation=True):
@ -124,7 +131,12 @@ class KeystoneClientV3(object):
return self.create_trust(trustee_user, role_names, impersonation) return self.create_trust(trustee_user, role_names, impersonation)
def delete_trust(self, trust_id): def delete_trust(self, trust_id):
if trust_id is None:
return
try: try:
self.client.trusts.delete(trust_id) self.client.trusts.delete(trust_id)
except kc_exception.NotFound: except kc_exception.NotFound:
pass pass
except Exception as e:
LOG.exception(str(e))
raise exception.TrustDeleteFailed(trust_id=trust_id)

View File

@ -51,8 +51,19 @@ bay_heat_opts = [
'interval is in minutes. The default is no timeout.')) 'interval is in minutes. The default is no timeout.'))
] ]
cfg.CONF.register_opts(bay_heat_opts, group='bay_heat') docker_registry_opts = [
cfg.StrOpt('trustee_user_id',
default=None,
help='User id of the trustee'),
cfg.ListOpt('trust_roles',
default=['registry_user'],
help='The roles which are delegated to the trustee '
'by the trustor.')
]
CONF = cfg.CONF
CONF.register_opts(bay_heat_opts, group='bay_heat')
CONF.register_opts(docker_registry_opts, 'docker_registry')
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -123,6 +134,14 @@ class Handler(object):
osc = clients.OpenStackClients(context) osc = clients.OpenStackClients(context)
baymodel = objects.BayModel.get_by_uuid(context,
bay.baymodel_id)
if baymodel.registry_enabled:
trust = osc.keystone().create_trust(
CONF.docker_registry.trustee_user_id,
CONF.docker_registry.trust_roles)
bay.registry_trust_id = trust.id
try: try:
# Generate certificate and set the cert reference to bay # Generate certificate and set the cert reference to bay
bay.uuid = uuid.uuid4() bay.uuid = uuid.uuid4()
@ -199,6 +218,7 @@ class Handler(object):
except Exception: except Exception:
raise raise
osc.keystone().delete_trust(bay.registry_trust_id)
self._poll_and_check(osc, bay) self._poll_and_check(osc, bay)
return None return None

View File

@ -0,0 +1,31 @@
# 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.
"""add registry_trust_id to bay
Revision ID: adc3b7679ae
Revises: 40f325033343
Create Date: 2015-12-07 15:49:07.622122
"""
# revision identifiers, used by Alembic.
revision = 'adc3b7679ae'
down_revision = '40f325033343'
from alembic import op
import sqlalchemy as sa
def upgrade():
op.add_column('bay', sa.Column('registry_trust_id',
sa.String(length=255), nullable=True))

View File

@ -120,6 +120,8 @@ class Bay(Base):
bay_create_timeout = Column(Integer()) bay_create_timeout = Column(Integer())
discovery_url = Column(String(255)) discovery_url = Column(String(255))
master_addresses = Column(JSONEncodedList) master_addresses = Column(JSONEncodedList)
# TODO(wanghua): encrypt registry_trust_id in db
registry_trust_id = Column(String(255))
# (yuanying) if we use barbican, # (yuanying) if we use barbican,
# cert_ref size is determined by below format # cert_ref size is determined by below format
# * http(s)://${DOMAIN_NAME}/v1/containers/${UUID} # * http(s)://${DOMAIN_NAME}/v1/containers/${UUID}

View File

@ -27,7 +27,8 @@ class Bay(base.MagnumPersistentObject, base.MagnumObject,
base.MagnumObjectDictCompat): base.MagnumObjectDictCompat):
# Version 1.0: Initial version # Version 1.0: Initial version
# Version 1.1: Added 'bay_create_timeout' field # Version 1.1: Added 'bay_create_timeout' field
VERSION = '1.1' # Version 1.2: Add 'registry_trust_id' field
VERSION = '1.2'
dbapi = dbapi.get_instance() dbapi = dbapi.get_instance()
@ -50,6 +51,7 @@ class Bay(base.MagnumPersistentObject, base.MagnumObject,
'master_addresses': fields.ListOfStringsField(nullable=True), 'master_addresses': fields.ListOfStringsField(nullable=True),
'ca_cert_ref': fields.StringField(nullable=True), 'ca_cert_ref': fields.StringField(nullable=True),
'magnum_cert_ref': fields.StringField(nullable=True), 'magnum_cert_ref': fields.StringField(nullable=True),
'registry_trust_id': fields.StringField(nullable=True)
} }
@staticmethod @staticmethod

View File

@ -46,6 +46,8 @@ def list_opts():
('conductor', magnum.conductor.config.SERVICE_OPTS), ('conductor', magnum.conductor.config.SERVICE_OPTS),
('database', magnum.db.sql_opts), ('database', magnum.db.sql_opts),
('docker', magnum.common.docker_utils.docker_opts), ('docker', magnum.common.docker_utils.docker_opts),
('docker_registry',
magnum.conductor.handlers.bay_conductor.docker_registry_opts),
('magnum_client', magnum.common.clients.magnum_client_opts), ('magnum_client', magnum.common.clients.magnum_client_opts),
('heat_client', magnum.common.clients.heat_client_opts), ('heat_client', magnum.common.clients.heat_client_opts),
('glance_client', magnum.common.clients.glance_client_opts), ('glance_client', magnum.common.clients.glance_client_opts),

View File

@ -49,7 +49,8 @@ class KeystoneClientTest(base.BaseTestCase):
ks_client.client ks_client.client
self.assertIsNotNone(ks_client._client) self.assertIsNotNone(ks_client._client)
mock_ks.assert_called_once_with(token='abcd1234', mock_ks.assert_called_once_with(token='abcd1234',
auth_url='http://server.test:5000/v3') auth_url='http://server.test:5000/v3',
endpoint='http://server.test:5000/v3')
def test_client_with_no_credentials(self, mock_ks): def test_client_with_no_credentials(self, mock_ks):
self.ctx.auth_token = None self.ctx.auth_token = None
@ -65,6 +66,7 @@ class KeystoneClientTest(base.BaseTestCase):
self.assertIsNotNone(ks_client._client) self.assertIsNotNone(ks_client._client)
mock_ks.assert_called_once_with(auth_ref={'version': 'v2.0'}, mock_ks.assert_called_once_with(auth_ref={'version': 'v2.0'},
auth_url='http://server.test:5000/v3', auth_url='http://server.test:5000/v3',
endpoint='http://server.test:5000/v3',
token='abcd1234') token='abcd1234')
def test_client_with_v3_auth_token_info(self, mock_ks): def test_client_with_v3_auth_token_info(self, mock_ks):
@ -75,6 +77,7 @@ class KeystoneClientTest(base.BaseTestCase):
self.assertIsNotNone(ks_client._client) self.assertIsNotNone(ks_client._client)
mock_ks.assert_called_once_with(auth_ref={'version': 'v3'}, mock_ks.assert_called_once_with(auth_ref={'version': 'v3'},
auth_url='http://server.test:5000/v3', auth_url='http://server.test:5000/v3',
endpoint='http://server.test:5000/v3',
token='abcd1234') token='abcd1234')
def test_client_with_invalid_auth_token_info(self, mock_ks): def test_client_with_invalid_auth_token_info(self, mock_ks):

View File

@ -95,6 +95,8 @@ def get_test_bay(**kw):
'node_count': kw.get('node_count', 3), 'node_count': kw.get('node_count', 3),
'master_count': kw.get('master_count', 3), 'master_count': kw.get('master_count', 3),
'master_addresses': kw.get('master_addresses', ['172.17.2.18']), 'master_addresses': kw.get('master_addresses', ['172.17.2.18']),
'registry_trust_id': kw.get('registry_trust_id',
'1f2281ac-e532-4e53-bbe6-3c9be24b0504'),
'created_at': kw.get('created_at'), 'created_at': kw.get('created_at'),
'updated_at': kw.get('updated_at'), 'updated_at': kw.get('updated_at'),
} }

View File

@ -423,7 +423,7 @@ class _TestObject(object):
# For more information on object version testing, read # For more information on object version testing, read
# http://docs.openstack.org/developer/magnum/objects.html # http://docs.openstack.org/developer/magnum/objects.html
object_data = { object_data = {
'Bay': '1.1-aa9937c7453c0fdb9165bd2a83640ed9', 'Bay': '1.2-0749bac339a2cc24dc03f45a4359013d',
'BayLock': '1.0-7d1eb08cf2070523bd210369c7a2e076', 'BayLock': '1.0-7d1eb08cf2070523bd210369c7a2e076',
'BayModel': '1.8-a4bb0976be245f06edbd1db087a18071', 'BayModel': '1.8-a4bb0976be245f06edbd1db087a18071',
'Certificate': '1.0-2aff667971b85c1edf8d15684fd7d5e2', 'Certificate': '1.0-2aff667971b85c1edf8d15684fd7d5e2',