diff --git a/api-ref/source/v2/images-sharing-v2.inc b/api-ref/source/v2/images-sharing-v2.inc index feda75bc0c..b4abe58a98 100644 --- a/api-ref/source/v2/images-sharing-v2.inc +++ b/api-ref/source/v2/images-sharing-v2.inc @@ -12,24 +12,14 @@ to create, list, update, and delete image members. .. note:: An image member is an identifier for a consumer with whom the image is - shared. In most OpenStack clouds, where the value of the ``owner`` property + shared. In OpenStack clouds, where the value of the ``owner`` property of an image is a project ID, the appropriate identifier to use for the - ``member_id`` is the consumer's project ID (also known as the "tenant ID"). - In these clouds, image sharing is project-to-project, and all the individual - users in the consuming project have access to the image. + ``member_id`` is the consumer's project ID (which used to be called the + "tenant ID"). - * Some deployments may choose instead to have the identifier of the user who - created the image as the value of the ``owner`` property. In such clouds, - the appropriate identifier to use for the ``member_id`` is the user ID of - the person with whom you want to share the image. In these clouds, image - sharing is user-to-user. - - * Note that you, as an image owner, do not have a choice about what value to - use for the ``member_id``. If, like most OpenStack clouds, your cloud - uses the tenant ID for the image ``owner``, sharing will not work if you - use a user ID as the ``member_id`` of an image (and vice-versa). - - * Please consult your cloud's local documentation for details. + * Image sharing is project-to-project. Thus *all the individual users + in the consuming project have access to the image*. You cannot share + an image with only one specific user in the target project. When an image is shared, the member is given immediate access to the image. In order to prevent spamming other users' image lists, a shared image does not diff --git a/doc/source/user/glanceapi.rst b/doc/source/user/glanceapi.rst index a23be7888b..3f1b80a958 100644 --- a/doc/source/user/glanceapi.rst +++ b/doc/source/user/glanceapi.rst @@ -579,8 +579,7 @@ The list of metadata headers that Glance accepts are listed below. This header is optional and only meaningful for admins. - Glance normally sets the owner of an image to be the tenant or user - (depending on the "owner_is_tenant" configuration option) of the + Glance sets the owner of an image to be the tenant of the authenticated user issuing the request. However, if the authenticated user has the Admin role, this default may be overridden by setting this header to null or to a string identifying the owner of the image. @@ -628,10 +627,10 @@ See more about image statuses here: :ref:`image-statuses` List Image Memberships ********************** -We want to see a list of the other system tenants (or users, if -"owner_is_tenant" is False) that may access a given virtual machine image that -the Glance server knows about. We take the `uri` field of the image data, -append ``/members`` to it, and issue a ``GET`` request on the resulting URL. +We want to see a list of the other system tenants that may access a given +virtual machine image that the Glance server knows about. We take the `uri` +field of the image data, append ``/members`` to it, and issue a ``GET`` request +on the resulting URL. Continuing from the example above, in order to get the memberships for the first image returned, we can issue a ``GET`` request to the Glance diff --git a/etc/glance-api.conf b/etc/glance-api.conf index f9904e6124..1cee9b815c 100644 --- a/etc/glance-api.conf +++ b/etc/glance-api.conf @@ -4,35 +4,6 @@ # From glance.api # -# DEPRECATED: -# Set the image owner to tenant or the authenticated user. -# -# Assign a boolean value to determine the owner of an image. When set to -# True, the owner of the image is the tenant. When set to False, the -# owner of the image will be the authenticated user issuing the request. -# Setting it to False makes the image private to the associated user and -# sharing with other users within the same tenant (or "project") -# requires explicit image sharing via image membership. -# -# Possible values: -# * True -# * False -# -# Related options: -# * None -# -# (boolean value) -# This option is deprecated for removal since Rocky. -# Its value may be silently ignored in the future. -# Reason: -# The non-default setting for this option misaligns Glance with other -# OpenStack services with respect to resource ownership. Further, surveys -# indicate that this option is not used by operators. The option will be -# removed early in the 'S' development cycle following the standard OpenStack -# deprecation policy. As the option is not in wide use, no migration path is -# proposed. -#owner_is_tenant = true - # DEPRECATED: # Role used to identify an authenticated user as administrator. # diff --git a/glance/api/middleware/context.py b/glance/api/middleware/context.py index 159c1c19ea..1266381914 100644 --- a/glance/api/middleware/context.py +++ b/glance/api/middleware/context.py @@ -25,37 +25,6 @@ from glance.i18n import _, _LW context_opts = [ - cfg.BoolOpt('owner_is_tenant', - default=True, - deprecated_for_removal=True, - deprecated_since="Rocky", - deprecated_reason=_(""" -The non-default setting for this option misaligns Glance with other -OpenStack services with respect to resource ownership. Further, surveys -indicate that this option is not used by operators. The option will be -removed early in the 'S' development cycle following the standard OpenStack -deprecation policy. As the option is not in wide use, no migration path is -proposed. -"""), - help=_(""" -Set the image owner to tenant or the authenticated user. - -Assign a boolean value to determine the owner of an image. When set to -True, the owner of the image is the tenant. When set to False, the -owner of the image will be the authenticated user issuing the request. -Setting it to False makes the image private to the associated user and -sharing with other users within the same tenant (or "project") -requires explicit image sharing via image membership. - -Possible values: - * True - * False - -Related options: - * None - -""")), - cfg.BoolOpt('allow_anonymous_access', default=False, help=_(""" Allow limited access to unauthenticated users. @@ -171,7 +140,6 @@ class ContextMiddleware(BaseContextMiddleware): return webob.exc.HTTPRequestHeaderFieldsTooLarge(comment=msg) kwargs = { - 'owner_is_tenant': CONF.owner_is_tenant, 'service_catalog': service_catalog, 'policy_enforcer': self.policy_enforcer, 'request_id': request_id, diff --git a/glance/cmd/status.py b/glance/cmd/status.py index 224f2cf7cb..86ee21ce25 100644 --- a/glance/cmd/status.py +++ b/glance/cmd/status.py @@ -19,6 +19,7 @@ from oslo_config import cfg from oslo_upgradecheck import common_checks from oslo_upgradecheck import upgradecheck +from glance.common import removed_config from glance.common import wsgi # noqa CONF = cfg.CONF @@ -30,6 +31,10 @@ FAILURE = upgradecheck.Code.FAILURE class Checks(upgradecheck.UpgradeCommands): """Programmable upgrade checks.""" + def __init__(self, *args, **kwargs): + super(upgradecheck.UpgradeCommands).__init__(*args, **kwargs) + removed_config.register_removed_options() + def _check_sheepdog_store(self): """Check that the removed sheepdog backend store is not configured.""" glance_store.register_opts(CONF) @@ -48,12 +53,23 @@ class Checks(upgradecheck.UpgradeCommands): return upgradecheck.Result(SUCCESS) + def _check_owner_is_tenant(self): + if CONF.owner_is_tenant is False: + return upgradecheck.Result( + FAILURE, + 'The "owner_is_tenant" option has been removed and there is ' + 'no upgrade path for installations that had this option set ' + 'to False.') + return upgradecheck.Result(SUCCESS) + _upgrade_checks = ( # Added in Ussuri ('Sheepdog Driver Removal', _check_sheepdog_store), # Added in Wallaby ('Policy File JSON to YAML Migration', (common_checks.check_policy_json, {'conf': CONF})), + # Removed in Wallaby + ('Config option owner_is_tenant removal', _check_owner_is_tenant), ) diff --git a/glance/common/removed_config.py b/glance/common/removed_config.py new file mode 100644 index 0000000000..b6c5991e66 --- /dev/null +++ b/glance/common/removed_config.py @@ -0,0 +1,34 @@ +# Copyright 2020 Red Hat, Inc +# All Rights Reserved. +# +# 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. +from glance.i18n import _ +from oslo_config import cfg + +removed_opts = [ + cfg.BoolOpt('owner_is_tenant', + default=True, + help=_(""" +This option has been removed in Wallaby. Because there is no migration path +for installations that had owner_is_tenant==False, we have defined this option +so that the code can probe the config file and refuse to start the api service +if the deployment has been using that setting. +""")), +] + + +def register_removed_options(): + # NOTE(cyril): This should only be called when we need to use options that + # have been removed and are therefore no longer relevant. This is the case + # of upgrade checks, for instance. + cfg.CONF.register_opts(removed_opts) diff --git a/glance/context.py b/glance/context.py index e8c431d5c8..a62b301f85 100644 --- a/glance/context.py +++ b/glance/context.py @@ -28,8 +28,7 @@ class RequestContext(context.RequestContext): """ - def __init__(self, owner_is_tenant=True, service_catalog=None, - policy_enforcer=None, **kwargs): + def __init__(self, service_catalog=None, policy_enforcer=None, **kwargs): # TODO(mriedem): Remove usage of user and tenant from old tests. if 'tenant' in kwargs: # Prefer project_id if passed, otherwise alias tenant as project_id @@ -40,7 +39,6 @@ class RequestContext(context.RequestContext): user = kwargs.pop('user') kwargs['user_id'] = kwargs.get('user_id', user) super(RequestContext, self).__init__(**kwargs) - self.owner_is_tenant = owner_is_tenant self.service_catalog = service_catalog self.policy_enforcer = policy_enforcer or policy.Enforcer() if not self.is_admin: @@ -67,7 +65,7 @@ class RequestContext(context.RequestContext): @property def owner(self): """Return the owner to correlate with an image.""" - return self.project_id if self.owner_is_tenant else self.user_id + return self.project_id @property def can_see_deleted(self): diff --git a/glance/tests/functional/__init__.py b/glance/tests/functional/__init__.py index 02c74c943d..ef9026b123 100644 --- a/glance/tests/functional/__init__.py +++ b/glance/tests/functional/__init__.py @@ -398,7 +398,6 @@ class ApiServer(Server): self.log_file = os.path.join(self.test_dir, "api.log") self.image_size_cap = 1099511627776 self.delayed_delete = delayed_delete - self.owner_is_tenant = True self.workers = 0 self.scrub_time = 5 self.image_cache_dir = os.path.join(self.test_dir, @@ -435,7 +434,6 @@ send_identity_credentials = %(send_identity_credentials)s log_file = %(log_file)s image_size_cap = %(image_size_cap)d delayed_delete = %(delayed_delete)s -owner_is_tenant = %(owner_is_tenant)s workers = %(workers)s scrub_time = %(scrub_time)s send_identity_headers = %(send_identity_headers)s @@ -567,7 +565,6 @@ class ApiServerForMultipleBackend(Server): self.log_file = os.path.join(self.test_dir, "multiple_backend_api.log") self.image_size_cap = 1099511627776 self.delayed_delete = delayed_delete - self.owner_is_tenant = True self.workers = 0 self.scrub_time = 5 self.image_cache_dir = os.path.join(self.test_dir, @@ -604,7 +601,6 @@ send_identity_credentials = %(send_identity_credentials)s log_file = %(log_file)s image_size_cap = %(image_size_cap)d delayed_delete = %(delayed_delete)s -owner_is_tenant = %(owner_is_tenant)s workers = %(workers)s scrub_time = %(scrub_time)s send_identity_headers = %(send_identity_headers)s diff --git a/glance/tests/functional/db/base.py b/glance/tests/functional/db/base.py index e7144add40..66731a511f 100644 --- a/glance/tests/functional/db/base.py +++ b/glance/tests/functional/db/base.py @@ -1096,11 +1096,9 @@ class DriverTests(object): TENANT1 = str(uuid.uuid4()) TENANT2 = str(uuid.uuid4()) ctxt1 = context.RequestContext(is_admin=False, tenant=TENANT1, - auth_token='user:%s:user' % TENANT1, - owner_is_tenant=True) - ctxt2 = context.RequestContext(is_admin=False, user=TENANT2, - auth_token='user:%s:user' % TENANT2, - owner_is_tenant=False) + auth_token='user:%s:user' % TENANT1) + ctxt2 = context.RequestContext(is_admin=False, tenant=TENANT2, + auth_token='user:%s:user' % TENANT2) UUIDX = str(uuid.uuid4()) # We need a shared image and context.owner should not match image # owner @@ -1149,11 +1147,9 @@ class DriverTests(object): TENANT1 = str(uuid.uuid4()) TENANT2 = str(uuid.uuid4()) ctxt1 = context.RequestContext(is_admin=False, tenant=TENANT1, - auth_token='user:%s:user' % TENANT1, - owner_is_tenant=True) - ctxt2 = context.RequestContext(is_admin=False, user=TENANT2, - auth_token='user:%s:user' % TENANT2, - owner_is_tenant=False) + auth_token='user:%s:user' % TENANT1) + ctxt2 = context.RequestContext(is_admin=False, tenant=TENANT2, + auth_token='user:%s:user' % TENANT2) UUIDX = str(uuid.uuid4()) # We need a shared image and context.owner should not match image # owner @@ -1180,10 +1176,10 @@ class DriverTests(object): TENANT2 = str(uuid.uuid4()) owners_ctxt = context.RequestContext(is_admin=False, tenant=TENANT1, auth_token='user:%s:user' - % TENANT1, owner_is_tenant=True) + % TENANT1) viewing_ctxt = context.RequestContext(is_admin=False, user=TENANT2, auth_token='user:%s:user' - % TENANT2, owner_is_tenant=False) + % TENANT2) UUIDX = str(uuid.uuid4()) # We need a community image and context.owner should not match image # owner diff --git a/glance/tests/unit/cmd/test_status.py b/glance/tests/unit/cmd/test_status.py index b45dceda88..ebc0cabb1c 100644 --- a/glance/tests/unit/cmd/test_status.py +++ b/glance/tests/unit/cmd/test_status.py @@ -65,3 +65,12 @@ class TestUpgradeChecks(test_utils.BaseTestCase): self.config(stores='sheepdog', group='glance_store') self.assertEqual(self.checker._check_sheepdog_store().code, upgradecheck.Code.FAILURE) + + def test_owner_is_tenant_removal(self): + self.config(owner_is_tenant=True) + self.assertEqual(self.checker._check_owner_is_tenant().code, + upgradecheck.Code.SUCCESS) + + self.config(owner_is_tenant=False) + self.assertEqual(self.checker._check_owner_is_tenant().code, + upgradecheck.Code.FAILURE) diff --git a/releasenotes/notes/remove-owner_is_tenant-b30150def293effc.yaml b/releasenotes/notes/remove-owner_is_tenant-b30150def293effc.yaml new file mode 100644 index 0000000000..e7e2f04225 --- /dev/null +++ b/releasenotes/notes/remove-owner_is_tenant-b30150def293effc.yaml @@ -0,0 +1,9 @@ +--- +upgrade: + - The ``owner_is_tenant`` configuration option, which was deprecated in + Rocky, has been removed in this release. As announced in the spec + `Deprecate owner_is_tenant + `_, + given that an operator survey indicated that this option was only + used in its default value of ``True``, no database migration is + included in this release.