Browse Source

Add project-id and user-id when list server-groups

Currently, command "nova server-group-list" and
"nova server-group-get" doesn't return groups'
project id and user id information. It is really
hard to identify which group belong to which
project/user when admin user use this command
with option "--all-projects".

This patch add project-id and user-id to the list.
All os-server-groups APIs will contain the above
mentioned data in the response data.

DocImpact: This adds API microversion
APIImpact: Project id information will be returned for
os-servers-group API

Change-Id: I0405ed6271c33981578841cfade220758615b1fd
Implements: blueprint add-project-id-and-user-id
Partial-bug: #1481210
Depends-On: I167141676ef4f597a1c022c1fd5dc96fd55d02ad
tags/13.0.0.0b2
Kevin_Zheng 4 years ago
parent
commit
6c74a145bc
19 changed files with 260 additions and 80 deletions
  1. 11
    0
      doc/api_samples/os-server-groups/v2.13/server-groups-get-resp.json
  2. 13
    0
      doc/api_samples/os-server-groups/v2.13/server-groups-list-resp.json
  3. 6
    0
      doc/api_samples/os-server-groups/v2.13/server-groups-post-req.json
  4. 11
    0
      doc/api_samples/os-server-groups/v2.13/server-groups-post-resp.json
  5. 1
    1
      doc/api_samples/versions/v21-version-get-resp.json
  6. 1
    1
      doc/api_samples/versions/versions-get-resp.json
  7. 2
    1
      nova/api/openstack/api_version_request.py
  8. 18
    5
      nova/api/openstack/compute/server_groups.py
  9. 7
    0
      nova/api/openstack/rest_api_version_history.rst
  10. 11
    0
      nova/tests/functional/api_sample_tests/api_samples/os-server-groups/v2.13/server-groups-get-resp.json.tpl
  11. 13
    0
      nova/tests/functional/api_sample_tests/api_samples/os-server-groups/v2.13/server-groups-list-resp.json.tpl
  12. 6
    0
      nova/tests/functional/api_sample_tests/api_samples/os-server-groups/v2.13/server-groups-post-req.json.tpl
  13. 11
    0
      nova/tests/functional/api_sample_tests/api_samples/os-server-groups/v2.13/server-groups-post-resp.json.tpl
  14. 1
    1
      nova/tests/functional/api_sample_tests/api_samples/versions/v21-version-get-resp.json.tpl
  15. 1
    1
      nova/tests/functional/api_sample_tests/api_samples/versions/versions-get-resp.json.tpl
  16. 6
    0
      nova/tests/functional/api_sample_tests/test_server_groups.py
  17. 131
    68
      nova/tests/unit/api/openstack/compute/test_server_groups.py
  18. 2
    2
      nova/tests/unit/api/openstack/compute/test_versions.py
  19. 8
    0
      releasenotes/notes/bp-add-project-and-user-id-a560d087656157d4.yaml

+ 11
- 0
doc/api_samples/os-server-groups/v2.13/server-groups-get-resp.json View File

@@ -0,0 +1,11 @@
1
+{
2
+    "server_group": {
3
+        "id": "5bbcc3c4-1da2-4437-a48a-66f15b1b13f9",
4
+        "name": "test",
5
+        "policies": ["anti-affinity"],
6
+        "members": [],
7
+        "metadata": {},
8
+        "project_id": "c7c9f4f175e247acb56c108fd724d667",
9
+        "user_id": "fake"
10
+    }
11
+}

+ 13
- 0
doc/api_samples/os-server-groups/v2.13/server-groups-list-resp.json View File

@@ -0,0 +1,13 @@
1
+{
2
+    "server_groups": [
3
+        {
4
+            "id": "616fb98f-46ca-475e-917e-2563e5a8cd19",
5
+            "name": "test",
6
+            "policies": ["anti-affinity"],
7
+            "members": [],
8
+            "metadata": {},
9
+            "project_id": "c7c9f4f175e247acb56c108fd724d667",
10
+            "user_id": "fake"
11
+        }
12
+    ]
13
+}

+ 6
- 0
doc/api_samples/os-server-groups/v2.13/server-groups-post-req.json View File

@@ -0,0 +1,6 @@
1
+{
2
+    "server_group": {
3
+        "name": "test",
4
+        "policies": ["anti-affinity"]
5
+    }
6
+}

+ 11
- 0
doc/api_samples/os-server-groups/v2.13/server-groups-post-resp.json View File

@@ -0,0 +1,11 @@
1
+{
2
+    "server_group": {
3
+        "id": "5bbcc3c4-1da2-4437-a48a-66f15b1b13f9",
4
+        "name": "test",
5
+        "policies": ["anti-affinity"],
6
+        "members": [],
7
+        "metadata": {},
8
+        "project_id": "c7c9f4f175e247acb56c108fd724d667",
9
+        "user_id": "fake"
10
+    }
11
+}

+ 1
- 1
doc/api_samples/versions/v21-version-get-resp.json View File

@@ -19,7 +19,7 @@
19 19
             }
20 20
         ],
21 21
         "status": "CURRENT",
22
-        "version": "2.12",
22
+        "version": "2.13",
23 23
         "min_version": "2.1",
24 24
         "updated": "2013-07-23T11:33:21Z"
25 25
     }

+ 1
- 1
doc/api_samples/versions/versions-get-resp.json View File

@@ -22,7 +22,7 @@
22 22
                 }
23 23
             ],
24 24
             "status": "CURRENT",
25
-            "version": "2.12",
25
+            "version": "2.13",
26 26
             "min_version": "2.1",
27 27
             "updated": "2013-07-23T11:33:21Z"
28 28
         }

+ 2
- 1
nova/api/openstack/api_version_request.py View File

@@ -53,6 +53,7 @@ REST_API_VERSION_HISTORY = """REST API Version History:
53 53
              user.
54 54
     * 2.11 - Exposes forced_down attribute for os-services
55 55
     * 2.12 - Exposes VIF net-id in os-virtual-interfaces
56
+    * 2.13 - Add project id and user id information for os-server-groups API
56 57
 """
57 58
 
58 59
 # The minimum and maximum versions of the API supported
@@ -61,7 +62,7 @@ REST_API_VERSION_HISTORY = """REST API Version History:
61 62
 # Note(cyeoh): This only applies for the v2.1 API once microversions
62 63
 # support is fully merged. It does not affect the V2 API.
63 64
 _MIN_API_VERSION = "2.1"
64
-_MAX_API_VERSION = "2.12"
65
+_MAX_API_VERSION = "2.13"
65 66
 DEFAULT_API_VERSION = _MIN_API_VERSION
66 67
 
67 68
 

+ 18
- 5
nova/api/openstack/compute/server_groups.py View File

@@ -19,6 +19,7 @@ from oslo_log import log as logging
19 19
 import webob
20 20
 from webob import exc
21 21
 
22
+from nova.api.openstack import api_version_request
22 23
 from nova.api.openstack import common
23 24
 from nova.api.openstack.compute.schemas import server_groups as schema
24 25
 from nova.api.openstack import extensions
@@ -46,7 +47,7 @@ def _authorize_context(req):
46 47
 class ServerGroupController(wsgi.Controller):
47 48
     """The Server group API controller for the OpenStack API."""
48 49
 
49
-    def _format_server_group(self, context, group):
50
+    def _format_server_group(self, context, group, req_ver):
50 51
         # the id field has its value as the uuid of the server group
51 52
         # There is no 'uuid' key in server_group seen by clients.
52 53
         # In addition, clients see policies as a ["policy-name"] list;
@@ -66,17 +67,25 @@ class ServerGroupController(wsgi.Controller):
66 67
                 context, filters=filters)
67 68
             members = [instance.uuid for instance in instances]
68 69
         server_group['members'] = members
70
+        # Add project id information to the response data for
71
+        # API version v2.13
72
+        if req_ver >= api_version_request.APIVersionRequest("2.13"):
73
+            server_group['project_id'] = group.project_id
74
+            server_group['user_id'] = group.user_id
69 75
         return server_group
70 76
 
71 77
     @extensions.expected_errors(404)
72 78
     def show(self, req, id):
73 79
         """Return data about the given server group."""
80
+        req_ver = req.api_version_request
81
+
74 82
         context = _authorize_context(req)
75 83
         try:
76 84
             sg = objects.InstanceGroup.get_by_uuid(context, id)
77 85
         except nova.exception.InstanceGroupNotFound as e:
78 86
             raise webob.exc.HTTPNotFound(explanation=e.format_message())
79
-        return {'server_group': self._format_server_group(context, sg)}
87
+        return {'server_group': self._format_server_group(
88
+                context, sg, req_ver)}
80 89
 
81 90
     @wsgi.response(204)
82 91
     @extensions.expected_errors(404)
@@ -113,6 +122,8 @@ class ServerGroupController(wsgi.Controller):
113 122
     @extensions.expected_errors(())
114 123
     def index(self, req):
115 124
         """Returns a list of server groups."""
125
+        req_ver = req.api_version_request
126
+
116 127
         context = _authorize_context(req)
117 128
         project_id = context.project_id
118 129
         if 'all_projects' in req.GET and context.is_admin:
@@ -121,7 +132,7 @@ class ServerGroupController(wsgi.Controller):
121 132
             sgs = objects.InstanceGroupList.get_by_project_id(
122 133
                     context, project_id)
123 134
         limited_list = common.limited(sgs.objects, req)
124
-        result = [self._format_server_group(context, group)
135
+        result = [self._format_server_group(context, group, req_ver)
125 136
                   for group in limited_list]
126 137
         return {'server_groups': result}
127 138
 
@@ -129,6 +140,8 @@ class ServerGroupController(wsgi.Controller):
129 140
     @validation.schema(schema.create)
130 141
     def create(self, req, body):
131 142
         """Creates a new server group."""
143
+        req_ver = req.api_version_request
144
+
132 145
         context = _authorize_context(req)
133 146
 
134 147
         quotas = objects.Quotas(context=context)
@@ -152,8 +165,8 @@ class ServerGroupController(wsgi.Controller):
152 165
             raise exc.HTTPBadRequest(explanation=e)
153 166
 
154 167
         quotas.commit()
155
-
156
-        return {'server_group': self._format_server_group(context, sg)}
168
+        return {'server_group': self._format_server_group(context, sg,
169
+                                                           req_ver)}
157 170
 
158 171
 
159 172
 class ServerGroups(extensions.V21APIExtensionBase):

+ 7
- 0
nova/api/openstack/rest_api_version_history.rst View File

@@ -130,3 +130,10 @@ user documentation.
130 130
   Exposes VIF ``net-id`` attribute in ``os-virtual-interfaces``.
131 131
   User will be able to get Virtual Interfaces ``net-id`` in Virtual Interfaces
132 132
   list and can determine in which network a Virtual Interface is plugged into.
133
+
134
+2.13
135
+----
136
+
137
+  Add information ``project_id`` and ``user_id`` to ``os-server-groups``
138
+  API response data.
139
+

+ 11
- 0
nova/tests/functional/api_sample_tests/api_samples/os-server-groups/v2.13/server-groups-get-resp.json.tpl View File

@@ -0,0 +1,11 @@
1
+{
2
+    "server_group": {
3
+        "id": "%(id)s",
4
+        "name": "%(name)s",
5
+        "policies": ["anti-affinity"],
6
+        "members": [],
7
+        "metadata": {},
8
+        "project_id": "c7c9f4f175e247acb56c108fd724d667",
9
+        "user_id": "fake"
10
+    }
11
+}

+ 13
- 0
nova/tests/functional/api_sample_tests/api_samples/os-server-groups/v2.13/server-groups-list-resp.json.tpl View File

@@ -0,0 +1,13 @@
1
+{
2
+    "server_groups": [
3
+        {
4
+            "id": "%(id)s",
5
+            "name": "test",
6
+            "policies": ["anti-affinity"],
7
+            "members": [],
8
+            "metadata": {},
9
+            "project_id": "c7c9f4f175e247acb56c108fd724d667",
10
+            "user_id": "fake"
11
+        }
12
+   ]
13
+}

+ 6
- 0
nova/tests/functional/api_sample_tests/api_samples/os-server-groups/v2.13/server-groups-post-req.json.tpl View File

@@ -0,0 +1,6 @@
1
+{
2
+    "server_group": {
3
+        "name": "%(name)s",
4
+        "policies": ["anti-affinity"]
5
+    }
6
+}

+ 11
- 0
nova/tests/functional/api_sample_tests/api_samples/os-server-groups/v2.13/server-groups-post-resp.json.tpl View File

@@ -0,0 +1,11 @@
1
+{
2
+    "server_group": {
3
+        "id": "%(id)s",
4
+        "name": "%(name)s",
5
+        "policies": ["anti-affinity"],
6
+        "members": [],
7
+        "metadata": {},
8
+        "project_id": "c7c9f4f175e247acb56c108fd724d667",
9
+        "user_id": "fake"
10
+    }
11
+}

+ 1
- 1
nova/tests/functional/api_sample_tests/api_samples/versions/v21-version-get-resp.json.tpl View File

@@ -19,7 +19,7 @@
19 19
             }
20 20
         ],
21 21
         "status": "CURRENT",
22
-        "version": "2.12",
22
+        "version": "2.13",
23 23
         "min_version": "2.1",
24 24
         "updated": "2013-07-23T11:33:21Z"
25 25
     }

+ 1
- 1
nova/tests/functional/api_sample_tests/api_samples/versions/versions-get-resp.json.tpl View File

@@ -22,7 +22,7 @@
22 22
                 }
23 23
             ],
24 24
             "status": "CURRENT",
25
-            "version": "2.12",
25
+            "version": "2.13",
26 26
             "min_version": "2.1",
27 27
             "updated": "2013-07-23T11:33:21Z"
28 28
         }

+ 6
- 0
nova/tests/functional/api_sample_tests/test_server_groups.py View File

@@ -77,3 +77,9 @@ class ServerGroupsSampleJsonTest(api_sample_base.ApiSampleTestBaseV21):
77 77
         uuid = self._post_server_group()
78 78
         response = self._do_delete('os-server-groups/%s' % uuid)
79 79
         self.assertEqual(204, response.status_code)
80
+
81
+
82
+class ServerGroupsV213SampleJsonTest(api_sample_base.ApiSampleTestBaseV21):
83
+    extension_name = "os-server-groups"
84
+    request_api_version = '2.13'
85
+    scenarios = [('v2_13', {})]

+ 131
- 68
nova/tests/unit/api/openstack/compute/test_server_groups.py View File

@@ -16,6 +16,8 @@
16 16
 from oslo_utils import uuidutils
17 17
 import webob
18 18
 
19
+import mock
20
+
19 21
 from nova.api.openstack.compute.legacy_v2.contrib import server_groups
20 22
 from nova.api.openstack.compute import server_groups as sg_v21
21 23
 from nova.api.openstack import extensions
@@ -127,6 +129,120 @@ class ServerGroupTestV21(test.TestCase):
127 129
         ig_uuid = self._create_instance_group(ctx, members)
128 130
         return (ig_uuid, instances, members)
129 131
 
132
+    @mock.patch.object(nova.db, 'instance_group_get_all_by_project_id')
133
+    @mock.patch.object(nova.db, 'instance_group_get_all')
134
+    def _test_list_server_group_all(self,
135
+                                    mock_get_all,
136
+                                    mock_get_by_project,
137
+                                    api_version='2.1'):
138
+        policies = ['anti-affinity']
139
+        members = []
140
+        metadata = {}  # always empty
141
+        names = ['default-x', 'test']
142
+        p_id = 'project_id'
143
+        u_id = 'user_id'
144
+        if api_version >= '2.13':
145
+            sg1 = server_group_resp_template(id=str(1345),
146
+                                            name=names[0],
147
+                                            policies=policies,
148
+                                            members=members,
149
+                                            metadata=metadata,
150
+                                            project_id=p_id,
151
+                                            user_id=u_id)
152
+            sg2 = server_group_resp_template(id=str(891),
153
+                                            name=names[1],
154
+                                            policies=policies,
155
+                                            members=members,
156
+                                            metadata=metadata,
157
+                                            project_id=p_id,
158
+                                            user_id=u_id)
159
+        else:
160
+            sg1 = server_group_resp_template(id=str(1345),
161
+                                            name=names[0],
162
+                                            policies=policies,
163
+                                            members=members,
164
+                                            metadata=metadata)
165
+            sg2 = server_group_resp_template(id=str(891),
166
+                                            name=names[1],
167
+                                            policies=policies,
168
+                                            members=members,
169
+                                            metadata=metadata)
170
+        tenant_groups = [sg2]
171
+        all_groups = [sg1, sg2]
172
+
173
+        all = {'server_groups': all_groups}
174
+        tenant_specific = {'server_groups': tenant_groups}
175
+
176
+        def return_all_server_groups():
177
+            return [server_group_db(sg) for sg in all_groups]
178
+
179
+        mock_get_all.return_value = return_all_server_groups()
180
+
181
+        def return_tenant_server_groups():
182
+            return [server_group_db(sg) for sg in tenant_groups]
183
+
184
+        mock_get_by_project.return_value = return_tenant_server_groups()
185
+
186
+        path = '/os-server-groups?all_projects=True'
187
+
188
+        req = fakes.HTTPRequest.blank(path, use_admin_context=True,
189
+                                      version=api_version)
190
+        res_dict = self.controller.index(req)
191
+        self.assertEqual(all, res_dict)
192
+        req = fakes.HTTPRequest.blank(path,
193
+                                      version=api_version)
194
+        res_dict = self.controller.index(req)
195
+        self.assertEqual(tenant_specific, res_dict)
196
+
197
+    @mock.patch.object(nova.db, 'instance_group_get_all_by_project_id')
198
+    def _test_list_server_group_by_tenant(self, mock_get_by_project,
199
+                                         api_version='2.1'):
200
+        policies = ['anti-affinity']
201
+        members = []
202
+        metadata = {}  # always empty
203
+        names = ['default-x', 'test']
204
+        p_id = 'project_id'
205
+        u_id = 'user_id'
206
+        if api_version >= '2.13':
207
+            sg1 = server_group_resp_template(id=str(1345),
208
+                                            name=names[0],
209
+                                            policies=policies,
210
+                                            members=members,
211
+                                            metadata=metadata,
212
+                                            project_id=p_id,
213
+                                            user_id=u_id)
214
+            sg2 = server_group_resp_template(id=str(891),
215
+                                            name=names[1],
216
+                                            policies=policies,
217
+                                            members=members,
218
+                                            metadata=metadata,
219
+                                            project_id=p_id,
220
+                                            user_id=u_id)
221
+        else:
222
+            sg1 = server_group_resp_template(id=str(1345),
223
+                                            name=names[0],
224
+                                            policies=policies,
225
+                                            members=members,
226
+                                            metadata=metadata)
227
+            sg2 = server_group_resp_template(id=str(891),
228
+                                            name=names[1],
229
+                                            policies=policies,
230
+                                            members=members,
231
+                                            metadata=metadata)
232
+        groups = [sg1, sg2]
233
+        expected = {'server_groups': groups}
234
+
235
+        def return_server_groups():
236
+            return [server_group_db(sg) for sg in groups]
237
+
238
+        return_get_by_project = return_server_groups()
239
+        mock_get_by_project.return_value = return_get_by_project
240
+        path = '/os-server-groups'
241
+        self.req = fakes.HTTPRequest.blank(path,
242
+                                           version=api_version)
243
+        res_dict = self.controller.index(self.req)
244
+        self.assertEqual(expected, res_dict)
245
+
130 246
     def test_display_members(self):
131 247
         ctx = context.RequestContext('fake_user', 'fake')
132 248
         (ig_uuid, instances, members) = self._create_groups_and_instances(ctx)
@@ -262,76 +378,10 @@ class ServerGroupTestV21(test.TestCase):
262 378
                           self.controller.create, self.req, body=body)
263 379
 
264 380
     def test_list_server_group_by_tenant(self):
265
-        groups = []
266
-        policies = ['anti-affinity']
267
-        members = []
268
-        metadata = {}  # always empty
269
-        names = ['default-x', 'test']
270
-        sg1 = server_group_resp_template(id=str(1345),
271
-                                           name=names[0],
272
-                                           policies=policies,
273
-                                           members=members,
274
-                                           metadata=metadata)
275
-        sg2 = server_group_resp_template(id=str(891),
276
-                                           name=names[1],
277
-                                           policies=policies,
278
-                                           members=members,
279
-                                           metadata=metadata)
280
-        groups = [sg1, sg2]
281
-        expected = {'server_groups': groups}
282
-
283
-        def return_server_groups(context, project_id):
284
-            return [server_group_db(sg) for sg in groups]
285
-
286
-        self.stubs.Set(nova.db, 'instance_group_get_all_by_project_id',
287
-                       return_server_groups)
288
-
289
-        res_dict = self.controller.index(self.req)
290
-        self.assertEqual(res_dict, expected)
381
+        self._test_list_server_group_by_tenant(api_version='2.1')
291 382
 
292 383
     def test_list_server_group_all(self):
293
-        all_groups = []
294
-        tenant_groups = []
295
-        policies = ['anti-affinity']
296
-        members = []
297
-        metadata = {}  # always empty
298
-        names = ['default-x', 'test']
299
-        sg1 = server_group_resp_template(id=str(1345),
300
-                                           name=names[0],
301
-                                           policies=[],
302
-                                           members=members,
303
-                                           metadata=metadata)
304
-        sg2 = server_group_resp_template(id=str(891),
305
-                                           name=names[1],
306
-                                           policies=policies,
307
-                                           members=members,
308
-                                           metadata={})
309
-        tenant_groups = [sg2]
310
-        all_groups = [sg1, sg2]
311
-
312
-        all = {'server_groups': all_groups}
313
-        tenant_specific = {'server_groups': tenant_groups}
314
-
315
-        def return_all_server_groups(context):
316
-            return [server_group_db(sg) for sg in all_groups]
317
-
318
-        self.stubs.Set(nova.db, 'instance_group_get_all',
319
-                       return_all_server_groups)
320
-
321
-        def return_tenant_server_groups(context, project_id):
322
-            return [server_group_db(sg) for sg in tenant_groups]
323
-
324
-        self.stubs.Set(nova.db, 'instance_group_get_all_by_project_id',
325
-                       return_tenant_server_groups)
326
-
327
-        path = '/os-server-groups?all_projects=True'
328
-
329
-        req = fakes.HTTPRequest.blank(path, use_admin_context=True)
330
-        res_dict = self.controller.index(req)
331
-        self.assertEqual(res_dict, all)
332
-        req = fakes.HTTPRequest.blank(path)
333
-        res_dict = self.controller.index(req)
334
-        self.assertEqual(res_dict, tenant_specific)
384
+        self._test_list_server_group_all(api_version='2.1')
335 385
 
336 386
     def test_delete_server_group_by_id(self):
337 387
         sg = server_group_template(id='123')
@@ -373,3 +423,16 @@ class ServerGroupTestV2(ServerGroupTestV21):
373 423
         ext_mgr = extensions.ExtensionManager()
374 424
         ext_mgr.extensions = {}
375 425
         self.controller = server_groups.ServerGroupController(ext_mgr)
426
+
427
+
428
+class ServerGroupTestV213(ServerGroupTestV21):
429
+    wsgi_api_version = '2.13'
430
+
431
+    def _setup_controller(self):
432
+        self.controller = sg_v21.ServerGroupController()
433
+
434
+    def test_list_server_group_all(self):
435
+        self._test_list_server_group_all(api_version='2.13')
436
+
437
+    def test_list_server_group_by_tenant(self):
438
+        self._test_list_server_group_by_tenant(api_version='2.13')

+ 2
- 2
nova/tests/unit/api/openstack/compute/test_versions.py View File

@@ -66,7 +66,7 @@ EXP_VERSIONS = {
66 66
     "v2.1": {
67 67
         "id": "v2.1",
68 68
         "status": "CURRENT",
69
-        "version": "2.12",
69
+        "version": "2.13",
70 70
         "min_version": "2.1",
71 71
         "updated": "2013-07-23T11:33:21Z",
72 72
         "links": [
@@ -128,7 +128,7 @@ class VersionsTestV20(test.NoDBTestCase):
128 128
             {
129 129
                 "id": "v2.1",
130 130
                 "status": "CURRENT",
131
-                "version": "2.12",
131
+                "version": "2.13",
132 132
                 "min_version": "2.1",
133 133
                 "updated": "2013-07-23T11:33:21Z",
134 134
                 "links": [

+ 8
- 0
releasenotes/notes/bp-add-project-and-user-id-a560d087656157d4.yaml View File

@@ -0,0 +1,8 @@
1
+---
2
+features:
3
+  - |
4
+    Project-id and user-id are now also returned in
5
+    the return data of os-server-groups APIs. In order
6
+    to use this new feature, user have to contain the
7
+    header of request microversion v2.13 in the API
8
+    request.

Loading…
Cancel
Save