diff --git a/etc/magnum/magnum.conf.sample b/etc/magnum/magnum.conf.sample index 2125d79c0f..c913618db4 100644 --- a/etc/magnum/magnum.conf.sample +++ b/etc/magnum/magnum.conf.sample @@ -142,6 +142,10 @@ # (string value) #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) #fatal_deprecations = false @@ -194,6 +198,16 @@ # Shows whether zmq-messaging uses broker or not. (boolean value) #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 = 127.0.0.1 @@ -211,6 +225,11 @@ # messaging, messagingv2, routing, log, test, noop (multi valued) #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 = + # AMQP topic used for OpenStack notifications. (list value) # Deprecated group/name - [rpc_notifier2]/topics #notification_topics = notifications @@ -259,7 +278,7 @@ # Specify a timeout after which a gracefully shutdown server will # exit. Zero value means endless wait. (integer value) -#graceful_shutdown_timeout = 0 +#graceful_shutdown_timeout = 60 [api] @@ -320,7 +339,7 @@ # Location of template to build a swarm cluster on atomic. (string # 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 # value) @@ -363,23 +382,23 @@ # network drivers include flannel. (list value) #kubernetes_allowed_network_drivers = all -# Default network driver for kubernetes baymodels. +# Default network driver for kubernetes baymodels. (string value) #kubernetes_default_network_driver = flannel -# Allowed network drivers for docker swarm baymodels. Use 'all' keyword -# to allow all drivers supported for swarm baymodels. Supported -# network drivers include docker. (list value) +# Allowed network drivers for docker swarm baymodels. Use 'all' +# keyword to allow all drivers supported for swarm baymodels. +# Supported network drivers include docker and flannel. (list value) #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 -# Allowed network drivers for mesos baymodels. Use 'all' keyword -# to allow all drivers supported for mesos baymodels. Supported -# network drivers include docker. (list value) +# Allowed network drivers for mesos baymodels. Use 'all' keyword to +# allow all drivers supported for mesos baymodels. Supported network +# drivers include docker. (list value) #mesos_allowed_network_drivers = all -# Default network driver for mesos baymodels. +# Default network driver for mesos baymodels. (string value) #mesos_default_network_driver = docker @@ -418,7 +437,7 @@ # # 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 = # Indicate that the actual request can include user credentials @@ -448,7 +467,7 @@ # # 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 = # Indicate that the actual request can include user credentials @@ -596,7 +615,7 @@ # Default timeout in seconds for docker client operations. (integer # value) -#default_timeout = 10 +#default_timeout = 60 # If set, ignore any SSL validation issues (boolean value) #api_insecure = false @@ -614,6 +633,20 @@ #key_file = +[docker_registry] + +# +# From magnum +# + +# User id of the trustee (string value) +#trustee_user_id = + +# The roles which are delegated to the trustee by the trustor. (list +# value) +#trust_roles = registry_user + + [glance_client] # @@ -829,6 +862,14 @@ # Service tenant name. (string value) #admin_tenant_name = admin +# Authentication type to load (unknown value) +# Deprecated group/name - [DEFAULT]/auth_plugin +#auth_type = + +# Config Section from which to load plugin specific options (unknown +# value) +#auth_section = + [magnum_client] diff --git a/magnum/api/controllers/v1/bay.py b/magnum/api/controllers/v1/bay.py index 9b1bbed1f2..e79518babe 100644 --- a/magnum/api/controllers/v1/bay.py +++ b/magnum/api/controllers/v1/bay.py @@ -41,7 +41,8 @@ class BayPatchType(types.JsonPatchType): def internal_attrs(): internal_attrs = ['/api_address', '/node_addresses', '/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 diff --git a/magnum/common/exception.py b/magnum/common/exception.py index 845cdcd7bd..094b707b3f 100644 --- a/magnum/common/exception.py +++ b/magnum/common/exception.py @@ -540,3 +540,11 @@ class FlavorNotFound(ResourceNotFound): class NetworkNotFound(ResourceNotFound): 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.") diff --git a/magnum/common/keystone.py b/magnum/common/keystone.py index b1b42598d3..8bfedb136c 100644 --- a/magnum/common/keystone.py +++ b/magnum/common/keystone.py @@ -83,7 +83,8 @@ class KeystoneClientV3(object): return 'token' in auth_token_info 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: kwargs.update(self._get_admin_credentials()) kwargs['trust_id'] = self.context.trust_id @@ -112,11 +113,17 @@ class KeystoneClientV3(object): def create_trust(self, trustee_user, role_names, impersonation=True): trustor_user_id = self.client.auth_ref.user_id trustor_project_id = self.client.auth_ref.project_id - trust = self.client.trusts.create(trustor_user=trustor_user_id, - project=trustor_project_id, - trustee_user=trustee_user, - impersonation=impersonation, - role_names=role_names) + try: + trust = self.client.trusts.create( + trustor_user=trustor_user_id, + project=trustor_project_id, + 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 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) def delete_trust(self, trust_id): + if trust_id is None: + return try: self.client.trusts.delete(trust_id) except kc_exception.NotFound: pass + except Exception as e: + LOG.exception(str(e)) + raise exception.TrustDeleteFailed(trust_id=trust_id) diff --git a/magnum/conductor/handlers/bay_conductor.py b/magnum/conductor/handlers/bay_conductor.py index bd0bf86056..9a7e306f83 100644 --- a/magnum/conductor/handlers/bay_conductor.py +++ b/magnum/conductor/handlers/bay_conductor.py @@ -51,8 +51,19 @@ bay_heat_opts = [ '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__) @@ -123,6 +134,14 @@ class Handler(object): 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: # Generate certificate and set the cert reference to bay bay.uuid = uuid.uuid4() @@ -199,6 +218,7 @@ class Handler(object): except Exception: raise + osc.keystone().delete_trust(bay.registry_trust_id) self._poll_and_check(osc, bay) return None diff --git a/magnum/db/sqlalchemy/alembic/versions/adc3b7679ae_add_registry_trust_id_to_bay.py b/magnum/db/sqlalchemy/alembic/versions/adc3b7679ae_add_registry_trust_id_to_bay.py new file mode 100644 index 0000000000..c780d10f5e --- /dev/null +++ b/magnum/db/sqlalchemy/alembic/versions/adc3b7679ae_add_registry_trust_id_to_bay.py @@ -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)) diff --git a/magnum/db/sqlalchemy/models.py b/magnum/db/sqlalchemy/models.py index 2cede25d76..89b5fdf7b9 100644 --- a/magnum/db/sqlalchemy/models.py +++ b/magnum/db/sqlalchemy/models.py @@ -120,6 +120,8 @@ class Bay(Base): bay_create_timeout = Column(Integer()) discovery_url = Column(String(255)) master_addresses = Column(JSONEncodedList) + # TODO(wanghua): encrypt registry_trust_id in db + registry_trust_id = Column(String(255)) # (yuanying) if we use barbican, # cert_ref size is determined by below format # * http(s)://${DOMAIN_NAME}/v1/containers/${UUID} diff --git a/magnum/objects/bay.py b/magnum/objects/bay.py index 7b42f66232..56664bc089 100644 --- a/magnum/objects/bay.py +++ b/magnum/objects/bay.py @@ -27,7 +27,8 @@ class Bay(base.MagnumPersistentObject, base.MagnumObject, base.MagnumObjectDictCompat): # Version 1.0: Initial version # 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() @@ -50,6 +51,7 @@ class Bay(base.MagnumPersistentObject, base.MagnumObject, 'master_addresses': fields.ListOfStringsField(nullable=True), 'ca_cert_ref': fields.StringField(nullable=True), 'magnum_cert_ref': fields.StringField(nullable=True), + 'registry_trust_id': fields.StringField(nullable=True) } @staticmethod diff --git a/magnum/opts.py b/magnum/opts.py index 4f5bd3740f..eefa1b4eeb 100644 --- a/magnum/opts.py +++ b/magnum/opts.py @@ -46,6 +46,8 @@ def list_opts(): ('conductor', magnum.conductor.config.SERVICE_OPTS), ('database', magnum.db.sql_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), ('heat_client', magnum.common.clients.heat_client_opts), ('glance_client', magnum.common.clients.glance_client_opts), diff --git a/magnum/tests/unit/common/test_keystone.py b/magnum/tests/unit/common/test_keystone.py index af2d50b9e2..d8f7fdd33c 100644 --- a/magnum/tests/unit/common/test_keystone.py +++ b/magnum/tests/unit/common/test_keystone.py @@ -49,7 +49,8 @@ class KeystoneClientTest(base.BaseTestCase): ks_client.client self.assertIsNotNone(ks_client._client) 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): self.ctx.auth_token = None @@ -65,6 +66,7 @@ class KeystoneClientTest(base.BaseTestCase): self.assertIsNotNone(ks_client._client) mock_ks.assert_called_once_with(auth_ref={'version': 'v2.0'}, auth_url='http://server.test:5000/v3', + endpoint='http://server.test:5000/v3', token='abcd1234') def test_client_with_v3_auth_token_info(self, mock_ks): @@ -75,6 +77,7 @@ class KeystoneClientTest(base.BaseTestCase): self.assertIsNotNone(ks_client._client) mock_ks.assert_called_once_with(auth_ref={'version': 'v3'}, auth_url='http://server.test:5000/v3', + endpoint='http://server.test:5000/v3', token='abcd1234') def test_client_with_invalid_auth_token_info(self, mock_ks): diff --git a/magnum/tests/unit/db/utils.py b/magnum/tests/unit/db/utils.py index 0c81e01163..a46c175bdf 100644 --- a/magnum/tests/unit/db/utils.py +++ b/magnum/tests/unit/db/utils.py @@ -95,6 +95,8 @@ def get_test_bay(**kw): 'node_count': kw.get('node_count', 3), 'master_count': kw.get('master_count', 3), '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'), 'updated_at': kw.get('updated_at'), } diff --git a/magnum/tests/unit/objects/test_objects.py b/magnum/tests/unit/objects/test_objects.py index fa5ef1657d..365244b5dd 100644 --- a/magnum/tests/unit/objects/test_objects.py +++ b/magnum/tests/unit/objects/test_objects.py @@ -423,7 +423,7 @@ class _TestObject(object): # For more information on object version testing, read # http://docs.openstack.org/developer/magnum/objects.html object_data = { - 'Bay': '1.1-aa9937c7453c0fdb9165bd2a83640ed9', + 'Bay': '1.2-0749bac339a2cc24dc03f45a4359013d', 'BayLock': '1.0-7d1eb08cf2070523bd210369c7a2e076', 'BayModel': '1.8-a4bb0976be245f06edbd1db087a18071', 'Certificate': '1.0-2aff667971b85c1edf8d15684fd7d5e2',