Skip to content

Commit a308c44

Browse files
committed
Hide old images
Added new boolean column "os_hidden" in images table. Images where "os_hidden" = True will be omitted from the image list presented to the user. This will apply to all image visibilities. However, the images will continue to be discoverable. User can use filter "os_hidden=true" in GET v2/images call to see all hidden images. Implements: blueprint hidden-images Change-Id: If8f02ca94fdb8e1ac7a81853cd392988900172d1
1 parent 2f859ce commit a308c44

17 files changed

Lines changed: 465 additions & 9 deletions

File tree

glance/api/authorization.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ def __init__(self, base, context):
315315
min_disk = _immutable_attr('base', 'min_disk')
316316
min_ram = _immutable_attr('base', 'min_ram')
317317
protected = _immutable_attr('base', 'protected')
318+
os_hidden = _immutable_attr('base', 'os_hidden')
318319
locations = _immutable_attr('base', 'locations', proxy=ImmutableLocations)
319320
checksum = _immutable_attr('base', 'checksum')
320321
owner = _immutable_attr('base', 'owner')

glance/api/v2/images.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,14 @@ def index(self, req, marker=None, limit=None, sort_key=None,
169169
filters = {}
170170
filters['deleted'] = False
171171

172+
os_hidden = filters.get('os_hidden', 'false').lower()
173+
if os_hidden not in ['true', 'false']:
174+
message = _("Invalid value '%s' for 'os_hidden' filter."
175+
" Valid values are 'true' or 'false'.") % os_hidden
176+
raise webob.exc.HTTPBadRequest(explanation=message)
177+
# ensure the type of os_hidden is boolean
178+
filters['os_hidden'] = os_hidden == 'true'
179+
172180
protected = filters.get('protected')
173181
if protected is not None:
174182
if protected not in ['true', 'false']:
@@ -443,7 +451,7 @@ class RequestDeserializer(wsgi.JSONRequestDeserializer):
443451
_base_properties = ('checksum', 'created_at', 'container_format',
444452
'disk_format', 'id', 'min_disk', 'min_ram', 'name',
445453
'size', 'virtual_size', 'status', 'tags', 'owner',
446-
'updated_at', 'visibility', 'protected')
454+
'updated_at', 'visibility', 'protected', 'os_hidden')
447455
_available_sort_keys = ('name', 'status', 'container_format',
448456
'disk_format', 'size', 'id', 'created_at',
449457
'updated_at')
@@ -876,7 +884,7 @@ def _get_image_locations(image):
876884
attributes = ['name', 'disk_format', 'container_format',
877885
'visibility', 'size', 'virtual_size', 'status',
878886
'checksum', 'protected', 'min_ram', 'min_disk',
879-
'owner']
887+
'owner', 'os_hidden']
880888
for key in attributes:
881889
image_view[key] = getattr(image, key)
882890
image_view['id'] = image.image_id
@@ -999,6 +1007,11 @@ def get_base_properties():
9991007
'type': 'boolean',
10001008
'description': _('If true, image will not be deletable.'),
10011009
},
1010+
'os_hidden': {
1011+
'type': 'boolean',
1012+
'description': _('If true, image will not appear in default '
1013+
'image list response.'),
1014+
},
10021015
'checksum': {
10031016
'type': ['null', 'string'],
10041017
'readOnly': True,

glance/db/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,8 @@ def _format_image_from_db(self, db_image, db_tags):
136136
size=db_image['size'],
137137
virtual_size=db_image['virtual_size'],
138138
extra_properties=properties,
139-
tags=db_tags
139+
tags=db_tags,
140+
os_hidden=db_image['os_hidden'],
140141
)
141142

142143
def _format_image_to_db(self, image):
@@ -168,6 +169,7 @@ def _format_image_to_db(self, image):
168169
'virtual_size': image.virtual_size,
169170
'visibility': image.visibility,
170171
'properties': dict(image.extra_properties),
172+
'os_hidden': image.os_hidden
171173
}
172174

173175
def add(self, image):

glance/db/simple/api.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ def _image_format(image_id, **values):
230230
'updated_at': dt,
231231
'deleted_at': None,
232232
'deleted': False,
233+
'os_hidden': False
233234
}
234235

235236
locations = values.pop('locations', None)
@@ -258,6 +259,7 @@ def _filter_images(images, filters, context,
258259
status = None
259260

260261
visibility = filters.pop('visibility', None)
262+
os_hidden = filters.pop('os_hidden', False)
261263

262264
for image in images:
263265
member = image_member_find(context, image_id=image['id'],
@@ -267,6 +269,7 @@ def _filter_images(images, filters, context,
267269
image_is_public = image['visibility'] == 'public'
268270
image_is_community = image['visibility'] == 'community'
269271
image_is_shared = image['visibility'] == 'shared'
272+
image_is_hidden = image['os_hidden'] == True
270273
acts_as_admin = context.is_admin and not admin_as_user
271274
can_see = (image_is_public
272275
or image_is_community
@@ -299,6 +302,10 @@ def _filter_images(images, filters, context,
299302
if not image_is_public == is_public:
300303
continue
301304

305+
if os_hidden:
306+
if image_is_hidden:
307+
continue
308+
302309
to_add = True
303310
for k, value in six.iteritems(filters):
304311
key = k
@@ -727,7 +734,8 @@ def image_create(context, image_values, v1_mode=False):
727734
'virtual_size', 'checksum', 'locations', 'owner',
728735
'protected', 'is_public', 'container_format',
729736
'disk_format', 'created_at', 'updated_at', 'deleted',
730-
'deleted_at', 'properties', 'tags', 'visibility'])
737+
'deleted_at', 'properties', 'tags', 'visibility',
738+
'os_hidden'])
731739

732740
incorrect_keys = set(image_values.keys()) - allowed_keys
733741
if incorrect_keys:
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Copyright (C) 2018 RedHat Inc.
2+
# All Rights Reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
5+
# not use this file except in compliance with the License. You may obtain
6+
# a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
# License for the specific language governing permissions and limitations
14+
# under the License.
15+
16+
17+
def has_migrations(engine):
18+
"""Returns true if at least one data row can be migrated."""
19+
20+
return False
21+
22+
23+
def migrate(engine):
24+
"""Return the number of rows migrated."""
25+
26+
return 0
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Copyright (C) 2018 RedHat Inc.
2+
# All Rights Reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
5+
# not use this file except in compliance with the License. You may obtain
6+
# a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
# License for the specific language governing permissions and limitations
14+
# under the License.
15+
16+
17+
# revision identifiers, used by Alembic.
18+
revision = 'rocky_contract01'
19+
down_revision = 'queens_contract01'
20+
branch_labels = None
21+
depends_on = 'rocky_expand01'
22+
23+
24+
def upgrade():
25+
pass
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Copyright (C) 2018 RedHat Inc.
2+
# All Rights Reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
5+
# not use this file except in compliance with the License. You may obtain
6+
# a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
# License for the specific language governing permissions and limitations
14+
# under the License.
15+
16+
"""add os_hidden column to images table"""
17+
18+
from alembic import op
19+
from sqlalchemy import Boolean, Column, sql
20+
21+
# revision identifiers, used by Alembic.
22+
revision = 'rocky_expand01'
23+
down_revision = 'queens_expand01'
24+
branch_labels = None
25+
depends_on = None
26+
27+
28+
def upgrade():
29+
h_col = Column('os_hidden', Boolean, default=False, nullable=False,
30+
server_default=sql.expression.false())
31+
op.add_column('images', h_col)
32+
op.create_index('os_hidden_image_idx', 'images', ['os_hidden'])

glance/db/sqlalchemy/api.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,10 @@ def _make_conditions_from_filters(filters, is_public=None):
460460
else:
461461
image_conditions.append(models.Image.visibility != 'public')
462462

463+
if 'os_hidden' in filters:
464+
os_hidden = filters.pop('os_hidden')
465+
image_conditions.append(models.Image.os_hidden == os_hidden)
466+
463467
if 'checksum' in filters:
464468
checksum = filters.pop('checksum')
465469
image_conditions.append(models.Image.checksum == checksum)

glance/db/sqlalchemy/models.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ class Image(BASE, GlanceBase):
119119
Index('ix_images_deleted', 'deleted'),
120120
Index('owner_image_idx', 'owner'),
121121
Index('created_at_image_idx', 'created_at'),
122-
Index('updated_at_image_idx', 'updated_at'))
122+
Index('updated_at_image_idx', 'updated_at'),
123+
Index('os_hidden_image_idx', 'os_hidden'))
123124

124125
id = Column(String(36), primary_key=True,
125126
default=lambda: str(uuid.uuid4()))
@@ -138,6 +139,8 @@ class Image(BASE, GlanceBase):
138139
owner = Column(String(255))
139140
protected = Column(Boolean, nullable=False, default=False,
140141
server_default=sql.expression.false())
142+
os_hidden = Column(Boolean, nullable=False, default=False,
143+
server_default=sql.expression.false())
141144

142145

143146
class ImageProperty(BASE, GlanceBase):

glance/domain/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ def _check_reserved(self, properties):
7171
def new_image(self, image_id=None, name=None, visibility='shared',
7272
min_disk=0, min_ram=0, protected=False, owner=None,
7373
disk_format=None, container_format=None,
74-
extra_properties=None, tags=None, **other_args):
74+
extra_properties=None, tags=None, os_hidden=False,
75+
**other_args):
7576
extra_properties = extra_properties or {}
7677
self._check_readonly(other_args)
7778
self._check_unexpected(other_args)
@@ -89,6 +90,7 @@ def new_image(self, image_id=None, name=None, visibility='shared',
8990
min_ram=min_ram, protected=protected,
9091
owner=owner, disk_format=disk_format,
9192
container_format=container_format,
93+
os_hidden=os_hidden,
9294
extra_properties=extra_properties, tags=tags or [])
9395

9496

@@ -119,6 +121,7 @@ def __init__(self, image_id, status, created_at, updated_at, **kwargs):
119121
self.updated_at = updated_at
120122
self.name = kwargs.pop('name', None)
121123
self.visibility = kwargs.pop('visibility', 'shared')
124+
self.os_hidden = kwargs.pop('os_hidden', False)
122125
self.min_disk = kwargs.pop('min_disk', 0)
123126
self.min_ram = kwargs.pop('min_ram', 0)
124127
self.protected = kwargs.pop('protected', False)

0 commit comments

Comments
 (0)