diff --git a/heat/engine/resources/openstack/keystone/project.py b/heat/engine/resources/openstack/keystone/project.py index 221b2c5784..2fdecf19d7 100644 --- a/heat/engine/resources/openstack/keystone/project.py +++ b/heat/engine/resources/openstack/keystone/project.py @@ -39,9 +39,9 @@ class KeystoneProject(resource.Resource): entity = 'projects' PROPERTIES = ( - NAME, DOMAIN, DESCRIPTION, ENABLED, PARENT, + NAME, DOMAIN, DESCRIPTION, ENABLED, PARENT, TAGS, ) = ( - 'name', 'domain', 'description', 'enabled', 'parent', + 'name', 'domain', 'description', 'enabled', 'parent', 'tags', ) properties_schema = { @@ -76,6 +76,13 @@ class KeystoneProject(resource.Resource): support_status=support.SupportStatus(version='6.0.0'), constraints=[constraints.CustomConstraint('keystone.project')] ), + TAGS: properties.Schema( + properties.Schema.LIST, + _('A list of tags for labeling and sorting projects.'), + support_status=support.SupportStatus(version='10.0.0'), + default=[], + update_allowed=True + ), } ATTRIBUTES = ( @@ -145,13 +152,15 @@ class KeystoneProject(resource.Resource): domain = self.properties[self.DOMAIN] enabled = self.properties[self.ENABLED] parent = self.properties[self.PARENT] + tags = self.properties[self.TAGS] project = self.client().projects.create( name=project_name, domain=domain, description=description, enabled=enabled, - parent=parent) + parent=parent, + tags=tags) self.resource_id_set(project.id) @@ -165,13 +174,16 @@ class KeystoneProject(resource.Resource): description = prop_diff.get(self.DESCRIPTION) enabled = prop_diff.get(self.ENABLED) domain = prop_diff.get(self.DOMAIN, self.properties[self.DOMAIN]) + tags = (prop_diff.get(self.TAGS) or + self.properties[self.TAGS]) self.client().projects.update( project=self.resource_id, name=name, description=description, enabled=enabled, - domain=domain + domain=domain, + tags=tags ) def parse_live_resource_data(self, resource_properties, resource_data): diff --git a/heat/tests/openstack/keystone/test_project.py b/heat/tests/openstack/keystone/test_project.py index 7634a3ca68..9b3c4ef63f 100644 --- a/heat/tests/openstack/keystone/test_project.py +++ b/heat/tests/openstack/keystone/test_project.py @@ -31,7 +31,8 @@ keystone_project_template = { 'description': 'Test project', 'domain': 'default', 'enabled': 'True', - 'parent': 'my_father' + 'parent': 'my_father', + 'tags': ['label', 'insignia'] } } } @@ -99,6 +100,9 @@ class KeystoneProjectTest(common.HeatTestCase): self.assertEqual( 'my_father', self.test_project.properties.get(project.KeystoneProject.PARENT)) + self.assertEqual( + ['label', 'insignia'], + self.test_project.properties.get(project.KeystoneProject.TAGS)) self.test_project.handle_create() @@ -108,7 +112,8 @@ class KeystoneProjectTest(common.HeatTestCase): description='Test project', domain='default', enabled=True, - parent='my_father') + parent='my_father', + tags=['label', 'insignia']) # validate physical resource id self.assertEqual(mock_project.id, self.test_project.resource_id) @@ -247,7 +252,10 @@ class KeystoneProjectTest(common.HeatTestCase): project.KeystoneProject.ENABLED)), project.KeystoneProject.PARENT: (self._get_property_schema_value_default( - project.KeystoneProject.PARENT)) + project.KeystoneProject.PARENT)), + project.KeystoneProject.TAGS: + (self._get_property_schema_value_default( + project.KeystoneProject.TAGS)) } def _side_effect(key): @@ -287,7 +295,8 @@ class KeystoneProjectTest(common.HeatTestCase): description='', domain='default', enabled=True, - parent=None) + parent=None, + tags=[]) def test_project_handle_update(self): self.test_project.resource_id = '477e8273-60a7-4c41-b683-fdb0bc7cd151' @@ -296,7 +305,8 @@ class KeystoneProjectTest(common.HeatTestCase): project.KeystoneProject.DESCRIPTION: 'Test Project updated', project.KeystoneProject.ENABLED: False, - project.KeystoneProject.DOMAIN: 'test_domain'} + project.KeystoneProject.DOMAIN: 'test_domain', + project.KeystoneProject.TAGS: ['tag1', 'tag2']} self.test_project.handle_update(json_snippet=None, tmpl_diff=None, @@ -307,7 +317,8 @@ class KeystoneProjectTest(common.HeatTestCase): name=prop_diff[project.KeystoneProject.NAME], description=prop_diff[project.KeystoneProject.DESCRIPTION], enabled=prop_diff[project.KeystoneProject.ENABLED], - domain='test_domain' + domain='test_domain', + tags=prop_diff[project.KeystoneProject.TAGS] ) def test_project_handle_update_default(self): @@ -315,7 +326,8 @@ class KeystoneProjectTest(common.HeatTestCase): prop_diff = {project.KeystoneProject.DESCRIPTION: 'Test Project updated', - project.KeystoneProject.ENABLED: False} + project.KeystoneProject.ENABLED: False, + project.KeystoneProject.TAGS: ['one', 'two']} self.test_project.handle_update(json_snippet=None, tmpl_diff=None, @@ -328,7 +340,8 @@ class KeystoneProjectTest(common.HeatTestCase): name=None, description=prop_diff[project.KeystoneProject.DESCRIPTION], enabled=prop_diff[project.KeystoneProject.ENABLED], - domain='default' + domain='default', + tags=prop_diff[project.KeystoneProject.TAGS] ) def test_project_handle_update_only_enabled(self): @@ -344,7 +357,8 @@ class KeystoneProjectTest(common.HeatTestCase): name=None, description=None, enabled=prop_diff[project.KeystoneProject.ENABLED], - domain='default' + domain='default', + tags=['label', 'insignia'] ) def test_show_resource(self): diff --git a/releasenotes/notes/project-tags-orchestration-If9125519e35f9f95ea8343cb07c377de9ccf5edf.yaml b/releasenotes/notes/project-tags-orchestration-If9125519e35f9f95ea8343cb07c377de9ccf5edf.yaml new file mode 100644 index 0000000000..e1ed9bf223 --- /dev/null +++ b/releasenotes/notes/project-tags-orchestration-If9125519e35f9f95ea8343cb07c377de9ccf5edf.yaml @@ -0,0 +1,5 @@ +--- +features: + - Add `tags` parameter for create and update keystone projects. + Defined comma deliniated list will insert tags into newly + created or updated projects.