Browse Source

Add Service Profile, shared attr, GBP namespace

Partially implements blueprint node-centric-chain-plugin

Changes namespace for Service Chain resources to OS:GroupBasedPolicy
Closes-bug: 1476803

Adds shared attribute for Service Chain resources
Closes-bug: 1475461

Also updates test-requirements to sync with global requirements.

Change-Id: I7c535dbadbe68ed5ba51f5ac63418af3100d7737
Sumit Naiksatam 3 years ago
parent
commit
e2d6566643

+ 106
- 6
gbpautomation/heat/engine/resources/servicechain.py View File

@@ -22,9 +22,9 @@ from neutronclient.common.exceptions import NeutronClientException
22 22
 class ServiceChainNode(gbpresource.GBPResource):
23 23
 
24 24
     PROPERTIES = (
25
-        TENANT_ID, NAME, DESCRIPTION, SERVICE_TYPE, CONFIG
25
+        TENANT_ID, NAME, DESCRIPTION, SERVICE_TYPE, CONFIG, SHARED
26 26
     ) = (
27
-        'tenant_id', 'name', 'description', 'service_type', 'config'
27
+        'tenant_id', 'name', 'description', 'service_type', 'config', 'shared'
28 28
     )
29 29
 
30 30
     properties_schema = {
@@ -53,6 +53,11 @@ class ServiceChainNode(gbpresource.GBPResource):
53 53
             _('Configuration of the service chain node.'),
54 54
             required=True,
55 55
             update_allowed=False
56
+        ),
57
+        SHARED: properties.Schema(
58
+            properties.Schema.BOOLEAN,
59
+            _('Shared.'),
60
+            update_allowed=True, required=True
56 61
         )
57 62
     }
58 63
 
@@ -95,9 +100,9 @@ class ServiceChainNode(gbpresource.GBPResource):
95 100
 class ServiceChainSpec(gbpresource.GBPResource):
96 101
 
97 102
     PROPERTIES = (
98
-        TENANT_ID, NAME, DESCRIPTION, NODES
103
+        TENANT_ID, NAME, DESCRIPTION, NODES, SHARED
99 104
     ) = (
100
-        'tenant_id', 'name', 'description', 'nodes'
105
+        'tenant_id', 'name', 'description', 'nodes', 'shared'
101 106
     )
102 107
 
103 108
     properties_schema = {
@@ -120,6 +125,11 @@ class ServiceChainSpec(gbpresource.GBPResource):
120 125
             _('Nodes in the service chain spec.'),
121 126
             required=True,
122 127
             update_allowed=True
128
+        ),
129
+        SHARED: properties.Schema(
130
+            properties.Schema.BOOLEAN,
131
+            _('Shared.'),
132
+            update_allowed=True, required=True
123 133
         )
124 134
     }
125 135
 
@@ -159,8 +169,98 @@ class ServiceChainSpec(gbpresource.GBPResource):
159 169
                 self.resource_id, {'servicechain_spec': prop_diff})
160 170
 
161 171
 
172
+class ServiceProfile(gbpresource.GBPResource):
173
+
174
+    PROPERTIES = (
175
+        TENANT_ID, NAME, DESCRIPTION, SHARED, VENDOR, INSERTION_MODE,
176
+        SERVICE_TYPE, SERVICE_FLAVOR
177
+    ) = (
178
+        'tenant_id', 'name', 'description', 'shared', 'vendor',
179
+        'insertion_mode', 'service_type', 'service_flavor'
180
+    )
181
+
182
+    properties_schema = {
183
+        TENANT_ID: properties.Schema(
184
+            properties.Schema.STRING,
185
+            _('Tenant id of the service profile.')
186
+        ),
187
+        NAME: properties.Schema(
188
+            properties.Schema.STRING,
189
+            _('Name of the service profile.'),
190
+            update_allowed=True
191
+        ),
192
+        DESCRIPTION: properties.Schema(
193
+            properties.Schema.STRING,
194
+            _('Description of the service profile.'),
195
+            update_allowed=True
196
+        ),
197
+        SHARED: properties.Schema(
198
+            properties.Schema.BOOLEAN,
199
+            _('Shared resource or not.'),
200
+            update_allowed=True
201
+        ),
202
+        VENDOR: properties.Schema(
203
+            properties.Schema.STRING,
204
+            _('Vendor providing the service node'),
205
+            update_allowed=True
206
+        ),
207
+        INSERTION_MODE: properties.Schema(
208
+            properties.Schema.STRING,
209
+            _('Insertion mode of the service'),
210
+            update_allowed=True
211
+        ),
212
+        SERVICE_TYPE: properties.Schema(
213
+            properties.Schema.STRING,
214
+            _('Type of the service.'),
215
+            required=True,
216
+            update_allowed=True
217
+        ),
218
+        SERVICE_FLAVOR: properties.Schema(
219
+            properties.Schema.STRING,
220
+            _('Flavor of the service'),
221
+            update_allowed=False
222
+        )
223
+    }
224
+
225
+    def _show_resource(self):
226
+        client = self.grouppolicy()
227
+        svc_profile_id = self.resource_id
228
+        return client.show_service_profile(svc_profile_id)['service_profile']
229
+
230
+    def handle_create(self):
231
+        client = self.grouppolicy()
232
+
233
+        props = {}
234
+        for key in self.properties:
235
+            if self.properties.get(key) is not None:
236
+                props[key] = self.properties.get(key)
237
+
238
+        svc_profile = client.create_service_profile(
239
+            {'service_profile': props})['service_profile']
240
+
241
+        self.resource_id_set(svc_profile['id'])
242
+
243
+    def handle_delete(self):
244
+
245
+        client = self.grouppolicy()
246
+        svc_profile_id = self.resource_id
247
+
248
+        try:
249
+            client.delete_service_profile(svc_profile_id)
250
+        except NeutronClientException as ex:
251
+            self.client_plugin().ignore_not_found(ex)
252
+        else:
253
+            return self._delete_task()
254
+
255
+    def handle_update(self, json_snippet, tmpl_diff, prop_diff):
256
+        if prop_diff:
257
+            self.grouppolicy().update_service_profile(
258
+                self.resource_id, {'service_profile': prop_diff})
259
+
260
+
162 261
 def resource_mapping():
163 262
     return {
164
-        'OS::ServiceChain::ServiceChainNode': ServiceChainNode,
165
-        'OS::ServiceChain::ServiceChainSpec': ServiceChainSpec,
263
+        'OS::GroupBasedPolicy::ServiceChainNode': ServiceChainNode,
264
+        'OS::GroupBasedPolicy::ServiceChainSpec': ServiceChainSpec,
265
+        'OS::GroupBasedPolicy::ServiceProfile': ServiceProfile,
166 266
     }

+ 151
- 4
gbpautomation/heat/tests/test_servicechain.py View File

@@ -26,14 +26,15 @@ from heat.tests import utils
26 26
 servicechain_node_template = '''
27 27
 {
28 28
   "AWSTemplateFormatVersion" : "2010-09-09",
29
-  "Description" : "Template to test neutron service chain node",
29
+  "Description" : "Template to test GBP service chain node",
30 30
   "Parameters" : {},
31 31
   "Resources" : {
32 32
     "servicechain_node": {
33
-      "Type": "OS::ServiceChain::ServiceChainNode",
33
+      "Type": "OS::GroupBasedPolicy::ServiceChainNode",
34 34
       "Properties": {
35 35
         "name": "test-sc-node",
36 36
         "description": "test service chain node resource",
37
+        "shared": True,
37 38
         "service_type": "TAP",
38 39
         "config": "{'name': 'sc_node_config'}"
39 40
       }
@@ -45,14 +46,15 @@ servicechain_node_template = '''
45 46
 servicechain_spec_template = '''
46 47
 {
47 48
   "AWSTemplateFormatVersion" : "2010-09-09",
48
-  "Description" : "Template to test neutron service chain spec",
49
+  "Description" : "Template to test GBP service chain spec",
49 50
   "Parameters" : {},
50 51
   "Resources" : {
51 52
     "servicechain_spec": {
52
-      "Type": "OS::ServiceChain::ServiceChainSpec",
53
+      "Type": "OS::GroupBasedPolicy::ServiceChainSpec",
53 54
       "Properties": {
54 55
         "name": "test-sc-spec",
55 56
         "description": "test service chain spec resource",
57
+        "shared": True,
56 58
         "nodes": ["1234", "7890"]
57 59
       }
58 60
     }
@@ -60,6 +62,28 @@ servicechain_spec_template = '''
60 62
 }
61 63
 '''
62 64
 
65
+service_profile_template = '''
66
+{
67
+  "AWSTemplateFormatVersion" : "2010-09-09",
68
+  "Description" : "Template to test GBP service profile",
69
+  "Parameters" : {},
70
+  "Resources" : {
71
+    "service_profile": {
72
+      "Type": "OS::GroupBasedPolicy::ServiceProfile",
73
+      "Properties": {
74
+        "name": "test-svc-profile",
75
+        "description": "test service profile resource",
76
+        "vendor": "test vendor",
77
+        "service_type": "test type",
78
+        "insertion_mode": "l2",
79
+        "service_flavor": "test flavor",
80
+        "shared": True
81
+      }
82
+    }
83
+  }
84
+}
85
+'''
86
+
63 87
 
64 88
 class ServiceChainNodeTest(HeatTestCase):
65 89
 
@@ -77,6 +101,7 @@ class ServiceChainNodeTest(HeatTestCase):
77 101
                 "name": "test-sc-node",
78 102
                 "description": "test service chain node resource",
79 103
                 "service_type": "TAP",
104
+                "shared": True,
80 105
                 "config": "{'name': 'sc_node_config'}"
81 106
             }
82 107
         }).AndReturn({'servicechain_node': {'id': '5678'}})
@@ -101,6 +126,7 @@ class ServiceChainNodeTest(HeatTestCase):
101 126
                 "name": "test-sc-node",
102 127
                 "description": "test service chain node resource",
103 128
                 "service_type": "TAP",
129
+                "shared": True,
104 130
                 "config": "{'name': 'sc_node_config'}"
105 131
             }
106 132
         }).AndRaise(servicechain.NeutronClientException())
@@ -190,6 +216,7 @@ class ServiceChainSpecTest(HeatTestCase):
190 216
             "servicechain_spec": {
191 217
                 "name": "test-sc-spec",
192 218
                 "description": "test service chain spec resource",
219
+                "shared": True,
193 220
                 "nodes": ["1234", "7890"]
194 221
             }
195 222
         }).AndReturn({'servicechain_spec': {'id': '5678'}})
@@ -213,6 +240,7 @@ class ServiceChainSpecTest(HeatTestCase):
213 240
             'servicechain_spec': {
214 241
                 "name": "test-sc-spec",
215 242
                 "description": "test service chain spec resource",
243
+                "shared": True,
216 244
                 "nodes": ["1234", "7890"]
217 245
             }
218 246
         }).AndRaise(servicechain.NeutronClientException())
@@ -285,3 +313,122 @@ class ServiceChainSpecTest(HeatTestCase):
285 313
         scheduler.TaskRunner(rsrc.update, update_template)()
286 314
 
287 315
         self.m.VerifyAll()
316
+
317
+
318
+class ServiceProfileTest(HeatTestCase):
319
+
320
+    def setUp(self):
321
+        super(ServiceProfileTest, self).setUp()
322
+        self.m.StubOutWithMock(gbpclient.Client, 'create_service_profile')
323
+        self.m.StubOutWithMock(gbpclient.Client, 'delete_service_profile')
324
+        self.m.StubOutWithMock(gbpclient.Client, 'show_service_profile')
325
+        self.m.StubOutWithMock(gbpclient.Client, 'update_service_profile')
326
+        self.stub_keystoneclient()
327
+
328
+    def create_service_profile(self):
329
+        gbpclient.Client.create_service_profile({
330
+            'service_profile': {
331
+                "name": "test-svc-profile",
332
+                "description": "test service profile resource",
333
+                "vendor": "test vendor",
334
+                "service_type": "test type",
335
+                "insertion_mode": "l2",
336
+                "service_flavor": "test flavor",
337
+                "shared": True
338
+            }
339
+        }).AndReturn({'service_profile': {'id': '5678'}})
340
+
341
+        snippet = template_format.parse(service_profile_template)
342
+        self.stack = utils.parse_stack(snippet)
343
+        resource_defns = self.stack.t.resource_definitions(self.stack)
344
+        return servicechain.ServiceProfile(
345
+            'service_profile', resource_defns['service_profile'], self.stack)
346
+
347
+    def test_create(self):
348
+        rsrc = self.create_service_profile()
349
+        self.m.ReplayAll()
350
+        scheduler.TaskRunner(rsrc.create)()
351
+        self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
352
+        self.m.VerifyAll()
353
+
354
+    def test_create_failed(self):
355
+        gbpclient.Client.create_service_profile({
356
+            'service_profile': {
357
+                "name": "test-svc-profile",
358
+                "description": "test service profile resource",
359
+                "vendor": "test vendor",
360
+                "service_type": "test type",
361
+                "insertion_mode": "l2",
362
+                "service_flavor": "test flavor",
363
+                "shared": True
364
+            }
365
+        }).AndRaise(servicechain.NeutronClientException())
366
+        self.m.ReplayAll()
367
+
368
+        snippet = template_format.parse(service_profile_template)
369
+        self.stack = utils.parse_stack(snippet)
370
+        resource_defns = self.stack.t.resource_definitions(self.stack)
371
+        rsrc = servicechain.ServiceProfile(
372
+            'service_profile', resource_defns['service_profile'],
373
+            self.stack)
374
+
375
+        error = self.assertRaises(exception.ResourceFailure,
376
+                                  scheduler.TaskRunner(rsrc.create))
377
+        self.assertEqual(
378
+            'NeutronClientException: resources.service_profile: '
379
+            'An unknown exception occurred.',
380
+            six.text_type(error))
381
+        self.assertEqual((rsrc.CREATE, rsrc.FAILED), rsrc.state)
382
+        self.m.VerifyAll()
383
+
384
+    def test_delete(self):
385
+        gbpclient.Client.delete_service_profile('5678')
386
+        gbpclient.Client.show_service_profile('5678').AndRaise(
387
+            servicechain.NeutronClientException(status_code=404))
388
+
389
+        rsrc = self.create_service_profile()
390
+        self.m.ReplayAll()
391
+        scheduler.TaskRunner(rsrc.create)()
392
+        scheduler.TaskRunner(rsrc.delete)()
393
+        self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state)
394
+        self.m.VerifyAll()
395
+
396
+    def test_delete_already_gone(self):
397
+        gbpclient.Client.delete_service_profile('5678').AndRaise(
398
+            servicechain.NeutronClientException(status_code=404))
399
+
400
+        rsrc = self.create_service_profile()
401
+        self.m.ReplayAll()
402
+        scheduler.TaskRunner(rsrc.create)()
403
+        scheduler.TaskRunner(rsrc.delete)()
404
+        self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state)
405
+        self.m.VerifyAll()
406
+
407
+    def test_delete_failed(self):
408
+        gbpclient.Client.delete_service_profile('5678').AndRaise(
409
+            servicechain.NeutronClientException(status_code=400))
410
+
411
+        rsrc = self.create_service_profile()
412
+        self.m.ReplayAll()
413
+        scheduler.TaskRunner(rsrc.create)()
414
+        error = self.assertRaises(exception.ResourceFailure,
415
+                                  scheduler.TaskRunner(rsrc.delete))
416
+        self.assertEqual(
417
+            'NeutronClientException: resources.service_profile: '
418
+            'An unknown exception occurred.',
419
+            six.text_type(error))
420
+        self.assertEqual((rsrc.DELETE, rsrc.FAILED), rsrc.state)
421
+        self.m.VerifyAll()
422
+
423
+    def test_update(self):
424
+        rsrc = self.create_service_profile()
425
+        gbpclient.Client.update_service_profile(
426
+            '5678', {'service_profile': {'name': 'profile_update'}})
427
+        self.m.ReplayAll()
428
+        scheduler.TaskRunner(rsrc.create)()
429
+
430
+        update_template = copy.deepcopy(rsrc.t)
431
+        update_template['Properties']['name'] = 'profile_update'
432
+        scheduler.TaskRunner(rsrc.update, update_template)()
433
+
434
+        self.m.VerifyAll()

+ 6
- 6
test-requirements.txt View File

@@ -8,14 +8,14 @@
8 8
 hacking<0.11,>=0.10.0
9 9
 coverage>=3.6
10 10
 discover
11
-mock>=1.0
12
-python-subunit>=0.0.18
11
+mock<1.1.0,>=1.0
13 12
 mox>=0.5.3
14 13
 MySQL-python
15
-oslosphinx>=2.5.0,<2.6.0  # Apache-2.0
16
-oslotest>=1.5.1,<1.6.0  # Apache-2.0
14
+oslosphinx<2.6.0,>=2.5.0 # Apache-2.0
15
+oslotest<1.6.0,>=1.5.1 # Apache-2.0
16
+paramiko>=1.13.0
17 17
 psycopg2
18
-sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3
18
+sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2
19 19
 testrepository>=0.0.18
20 20
 testscenarios>=0.4
21
-testtools>=0.9.36,!=1.2.0
21
+testtools!=1.2.0,>=0.9.36

Loading…
Cancel
Save