~ubuntu-branches/ubuntu/wily/heat/wily

« back to all changes in this revision

Viewing changes to heat/tests/engine/test_software_config.py

  • Committer: Package Import Robot
  • Author(s): Corey Bryant
  • Date: 2015-09-08 15:52:07 UTC
  • mfrom: (1.1.28)
  • Revision ID: package-import@ubuntu.com-20150908155207-zi2r1rckyrevr5u7
Tags: 1:5.0.0~b3-0ubuntu1
* New upstream milestone for OpenStack Liberty.
* d/control: Align (build-)depends with upstream.
* d/p/fix-dummy-resource-missing.patch: Dropped. Fixed in milestone.
* d/p/move-extensions.patch: Dropped. Fixed in milestone.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#
2
 
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
3
 
#    not use this file except in compliance with the License. You may obtain
4
 
#    a copy of the License at
5
 
#
6
 
#         http://www.apache.org/licenses/LICENSE-2.0
7
 
#
8
 
#    Unless required by applicable law or agreed to in writing, software
9
 
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10
 
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11
 
#    License for the specific language governing permissions and limitations
12
 
#    under the License.
13
 
 
14
 
import datetime
15
 
import uuid
16
 
 
17
 
import mock
18
 
from oslo_messaging.rpc import dispatcher
19
 
from oslo_serialization import jsonutils as json
20
 
from oslo_utils import timeutils
21
 
import six
22
 
 
23
 
from heat.common import exception
24
 
from heat.common import template_format
25
 
from heat.engine.clients.os import swift
26
 
from heat.engine.clients.os import zaqar
27
 
from heat.engine import service
28
 
from heat.engine import service_software_config
29
 
from heat.objects import resource as resource_objects
30
 
from heat.objects import software_deployment as software_deployment_object
31
 
from heat.tests import common
32
 
from heat.tests.engine import tools
33
 
from heat.tests import utils
34
 
 
35
 
 
36
 
class SoftwareConfigServiceTest(common.HeatTestCase):
37
 
 
38
 
    def setUp(self):
39
 
        super(SoftwareConfigServiceTest, self).setUp()
40
 
        self.ctx = utils.dummy_context()
41
 
        self.engine = service.EngineService('a-host', 'a-topic')
42
 
 
43
 
    def _create_software_config(
44
 
            self, group='Heat::Shell', name='config_mysql', config=None,
45
 
            inputs=None, outputs=None, options=None):
46
 
        inputs = inputs or []
47
 
        outputs = outputs or []
48
 
        options = options or {}
49
 
        return self.engine.create_software_config(
50
 
            self.ctx, group, name, config, inputs, outputs, options)
51
 
 
52
 
    def test_list_software_configs(self):
53
 
        config = self._create_software_config()
54
 
        config_id = config['id']
55
 
        self.assertIsNotNone(config)
56
 
 
57
 
        configs = self.engine.list_software_configs(self.ctx)
58
 
        self.assertIsNotNone(configs)
59
 
        config_ids = [x['id'] for x in configs]
60
 
        self.assertIn(config_id, config_ids)
61
 
 
62
 
    def test_show_software_config(self):
63
 
        config_id = str(uuid.uuid4())
64
 
 
65
 
        ex = self.assertRaises(dispatcher.ExpectedException,
66
 
                               self.engine.show_software_config,
67
 
                               self.ctx, config_id)
68
 
        self.assertEqual(exception.NotFound, ex.exc_info[0])
69
 
 
70
 
        config = self._create_software_config()
71
 
        res = self.engine.show_software_config(self.ctx, config['id'])
72
 
        self.assertEqual(config, res)
73
 
 
74
 
    def test_create_software_config_new_ids(self):
75
 
        config1 = self._create_software_config()
76
 
        self.assertIsNotNone(config1)
77
 
 
78
 
        config2 = self._create_software_config()
79
 
        self.assertNotEqual(config1['id'], config2['id'])
80
 
 
81
 
    def test_create_software_config(self):
82
 
        kwargs = {
83
 
            'group': 'Heat::Chef',
84
 
            'name': 'config_heat',
85
 
            'config': '...',
86
 
            'inputs': [{'name': 'mode'}],
87
 
            'outputs': [{'name': 'endpoint'}],
88
 
            'options': {}
89
 
        }
90
 
        config = self._create_software_config(**kwargs)
91
 
        config_id = config['id']
92
 
        config = self.engine.show_software_config(self.ctx, config_id)
93
 
        self.assertEqual(kwargs['group'], config['group'])
94
 
        self.assertEqual(kwargs['name'], config['name'])
95
 
        self.assertEqual(kwargs['config'], config['config'])
96
 
        self.assertEqual(kwargs['inputs'], config['inputs'])
97
 
        self.assertEqual(kwargs['outputs'], config['outputs'])
98
 
        self.assertEqual(kwargs['options'], config['options'])
99
 
 
100
 
    def test_delete_software_config(self):
101
 
        config = self._create_software_config()
102
 
        self.assertIsNotNone(config)
103
 
        config_id = config['id']
104
 
        self.engine.delete_software_config(self.ctx, config_id)
105
 
 
106
 
        ex = self.assertRaises(dispatcher.ExpectedException,
107
 
                               self.engine.show_software_config,
108
 
                               self.ctx, config_id)
109
 
        self.assertEqual(exception.NotFound, ex.exc_info[0])
110
 
 
111
 
    def _create_software_deployment(self, config_id=None, input_values=None,
112
 
                                    action='INIT',
113
 
                                    status='COMPLETE', status_reason='',
114
 
                                    config_group=None,
115
 
                                    server_id=str(uuid.uuid4()),
116
 
                                    config_name=None,
117
 
                                    stack_user_project_id=None):
118
 
        input_values = input_values or {}
119
 
        if config_id is None:
120
 
            config = self._create_software_config(group=config_group,
121
 
                                                  name=config_name)
122
 
            config_id = config['id']
123
 
        return self.engine.create_software_deployment(
124
 
            self.ctx, server_id, config_id, input_values,
125
 
            action, status, status_reason, stack_user_project_id)
126
 
 
127
 
    def test_list_software_deployments(self):
128
 
        stack_name = 'test_list_software_deployments'
129
 
        t = template_format.parse(tools.wp_template)
130
 
        stack = utils.parse_stack(t, stack_name=stack_name)
131
 
 
132
 
        tools.setup_mocks(self.m, stack)
133
 
        self.m.ReplayAll()
134
 
        stack.store()
135
 
        stack.create()
136
 
        server = stack['WebServer']
137
 
        server_id = server.resource_id
138
 
        deployment = self._create_software_deployment(
139
 
            server_id=server_id)
140
 
        deployment_id = deployment['id']
141
 
        self.assertIsNotNone(deployment)
142
 
 
143
 
        deployments = self.engine.list_software_deployments(
144
 
            self.ctx, server_id=None)
145
 
        self.assertIsNotNone(deployments)
146
 
        deployment_ids = [x['id'] for x in deployments]
147
 
        self.assertIn(deployment_id, deployment_ids)
148
 
        self.assertIn(deployment, deployments)
149
 
 
150
 
        deployments = self.engine.list_software_deployments(
151
 
            self.ctx, server_id=str(uuid.uuid4()))
152
 
        self.assertEqual([], deployments)
153
 
 
154
 
        deployments = self.engine.list_software_deployments(
155
 
            self.ctx, server_id=server.resource_id)
156
 
        self.assertEqual([deployment], deployments)
157
 
 
158
 
        rs = resource_objects.Resource.get_by_physical_resource_id(
159
 
            self.ctx, server_id)
160
 
        self.assertEqual(deployment['config_id'],
161
 
                         rs.rsrc_metadata.get('deployments')[0]['id'])
162
 
 
163
 
    def test_metadata_software_deployments(self):
164
 
        stack_name = 'test_metadata_software_deployments'
165
 
        t = template_format.parse(tools.wp_template)
166
 
        stack = utils.parse_stack(t, stack_name=stack_name)
167
 
 
168
 
        tools.setup_mocks(self.m, stack)
169
 
        self.m.ReplayAll()
170
 
        stack.store()
171
 
        stack.create()
172
 
        server = stack['WebServer']
173
 
        server_id = server.resource_id
174
 
 
175
 
        stack_user_project_id = str(uuid.uuid4())
176
 
        d1 = self._create_software_deployment(
177
 
            config_group='mygroup',
178
 
            server_id=server_id,
179
 
            config_name='02_second',
180
 
            stack_user_project_id=stack_user_project_id)
181
 
        d2 = self._create_software_deployment(
182
 
            config_group='mygroup',
183
 
            server_id=server_id,
184
 
            config_name='01_first',
185
 
            stack_user_project_id=stack_user_project_id)
186
 
        d3 = self._create_software_deployment(
187
 
            config_group='myothergroup',
188
 
            server_id=server_id,
189
 
            config_name='03_third',
190
 
            stack_user_project_id=stack_user_project_id)
191
 
        metadata = self.engine.metadata_software_deployments(
192
 
            self.ctx, server_id=server_id)
193
 
        self.assertEqual(3, len(metadata))
194
 
        self.assertEqual('mygroup', metadata[1]['group'])
195
 
        self.assertEqual('mygroup', metadata[0]['group'])
196
 
        self.assertEqual('myothergroup', metadata[2]['group'])
197
 
        self.assertEqual(d1['config_id'], metadata[1]['id'])
198
 
        self.assertEqual(d2['config_id'], metadata[0]['id'])
199
 
        self.assertEqual(d3['config_id'], metadata[2]['id'])
200
 
        self.assertEqual('01_first', metadata[0]['name'])
201
 
        self.assertEqual('02_second', metadata[1]['name'])
202
 
        self.assertEqual('03_third', metadata[2]['name'])
203
 
 
204
 
        # assert that metadata via metadata_software_deployments matches
205
 
        # metadata via server resource
206
 
        rs = resource_objects.Resource.get_by_physical_resource_id(
207
 
            self.ctx, server_id)
208
 
        self.assertEqual(metadata, rs.rsrc_metadata.get('deployments'))
209
 
 
210
 
        deployments = self.engine.metadata_software_deployments(
211
 
            self.ctx, server_id=str(uuid.uuid4()))
212
 
        self.assertEqual([], deployments)
213
 
 
214
 
        # assert get results when the context tenant_id matches
215
 
        # the stored stack_user_project_id
216
 
        ctx = utils.dummy_context(tenant_id=stack_user_project_id)
217
 
        metadata = self.engine.metadata_software_deployments(
218
 
            ctx, server_id=server_id)
219
 
        self.assertEqual(3, len(metadata))
220
 
 
221
 
        # assert get no results when the context tenant_id is unknown
222
 
        ctx = utils.dummy_context(tenant_id=str(uuid.uuid4()))
223
 
        metadata = self.engine.metadata_software_deployments(
224
 
            ctx, server_id=server_id)
225
 
        self.assertEqual(0, len(metadata))
226
 
 
227
 
    def test_show_software_deployment(self):
228
 
        deployment_id = str(uuid.uuid4())
229
 
        ex = self.assertRaises(dispatcher.ExpectedException,
230
 
                               self.engine.show_software_deployment,
231
 
                               self.ctx, deployment_id)
232
 
        self.assertEqual(exception.NotFound, ex.exc_info[0])
233
 
 
234
 
        deployment = self._create_software_deployment()
235
 
        self.assertIsNotNone(deployment)
236
 
        deployment_id = deployment['id']
237
 
        self.assertEqual(
238
 
            deployment,
239
 
            self.engine.show_software_deployment(self.ctx, deployment_id))
240
 
 
241
 
    @mock.patch.object(service_software_config.SoftwareConfigService,
242
 
                       '_push_metadata_software_deployments')
243
 
    def test_signal_software_deployment(self, pmsd):
244
 
        self.assertRaises(ValueError,
245
 
                          self.engine.signal_software_deployment,
246
 
                          self.ctx, None, {}, None)
247
 
        deployment_id = str(uuid.uuid4())
248
 
        ex = self.assertRaises(dispatcher.ExpectedException,
249
 
                               self.engine.signal_software_deployment,
250
 
                               self.ctx, deployment_id, {}, None)
251
 
        self.assertEqual(exception.NotFound, ex.exc_info[0])
252
 
 
253
 
        deployment = self._create_software_deployment()
254
 
        deployment_id = deployment['id']
255
 
 
256
 
        # signal is ignore unless deployment is IN_PROGRESS
257
 
        self.assertIsNone(self.engine.signal_software_deployment(
258
 
            self.ctx, deployment_id, {}, None))
259
 
 
260
 
        # simple signal, no data
261
 
        deployment = self._create_software_deployment(action='INIT',
262
 
                                                      status='IN_PROGRESS')
263
 
        deployment_id = deployment['id']
264
 
        res = self.engine.signal_software_deployment(
265
 
            self.ctx, deployment_id, {}, None)
266
 
        self.assertEqual('deployment succeeded', res)
267
 
 
268
 
        sd = software_deployment_object.SoftwareDeployment.get_by_id(
269
 
            self.ctx, deployment_id)
270
 
        self.assertEqual('COMPLETE', sd.status)
271
 
        self.assertEqual('Outputs received', sd.status_reason)
272
 
        self.assertEqual({
273
 
            'deploy_status_code': None,
274
 
            'deploy_stderr': None,
275
 
            'deploy_stdout': None
276
 
        }, sd.output_values)
277
 
        self.assertIsNotNone(sd.updated_at)
278
 
 
279
 
        # simple signal, some data
280
 
        config = self._create_software_config(outputs=[{'name': 'foo'}])
281
 
        deployment = self._create_software_deployment(
282
 
            config_id=config['id'], action='INIT', status='IN_PROGRESS')
283
 
        deployment_id = deployment['id']
284
 
        result = self.engine.signal_software_deployment(
285
 
            self.ctx,
286
 
            deployment_id,
287
 
            {'foo': 'bar', 'deploy_status_code': 0},
288
 
            None)
289
 
        self.assertEqual('deployment succeeded', result)
290
 
        sd = software_deployment_object.SoftwareDeployment.get_by_id(
291
 
            self.ctx, deployment_id)
292
 
        self.assertEqual('COMPLETE', sd.status)
293
 
        self.assertEqual('Outputs received', sd.status_reason)
294
 
        self.assertEqual({
295
 
            'deploy_status_code': 0,
296
 
            'foo': 'bar',
297
 
            'deploy_stderr': None,
298
 
            'deploy_stdout': None
299
 
        }, sd.output_values)
300
 
        self.assertIsNotNone(sd.updated_at)
301
 
 
302
 
        # failed signal on deploy_status_code
303
 
        config = self._create_software_config(outputs=[{'name': 'foo'}])
304
 
        deployment = self._create_software_deployment(
305
 
            config_id=config['id'], action='INIT', status='IN_PROGRESS')
306
 
        deployment_id = deployment['id']
307
 
        result = self.engine.signal_software_deployment(
308
 
            self.ctx,
309
 
            deployment_id,
310
 
            {
311
 
                'foo': 'bar',
312
 
                'deploy_status_code': -1,
313
 
                'deploy_stderr': 'Its gone Pete Tong'
314
 
            },
315
 
            None)
316
 
        self.assertEqual('deployment failed (-1)', result)
317
 
        sd = software_deployment_object.SoftwareDeployment.get_by_id(
318
 
            self.ctx, deployment_id)
319
 
        self.assertEqual('FAILED', sd.status)
320
 
        self.assertEqual(
321
 
            ('deploy_status_code : Deployment exited with non-zero '
322
 
             'status code: -1'),
323
 
            sd.status_reason)
324
 
        self.assertEqual({
325
 
            'deploy_status_code': -1,
326
 
            'foo': 'bar',
327
 
            'deploy_stderr': 'Its gone Pete Tong',
328
 
            'deploy_stdout': None
329
 
        }, sd.output_values)
330
 
        self.assertIsNotNone(sd.updated_at)
331
 
 
332
 
        # failed signal on error_output foo
333
 
        config = self._create_software_config(outputs=[
334
 
            {'name': 'foo', 'error_output': True}])
335
 
        deployment = self._create_software_deployment(
336
 
            config_id=config['id'], action='INIT', status='IN_PROGRESS')
337
 
        deployment_id = deployment['id']
338
 
        result = self.engine.signal_software_deployment(
339
 
            self.ctx,
340
 
            deployment_id,
341
 
            {
342
 
                'foo': 'bar',
343
 
                'deploy_status_code': -1,
344
 
                'deploy_stderr': 'Its gone Pete Tong'
345
 
            },
346
 
            None)
347
 
        self.assertEqual('deployment failed', result)
348
 
 
349
 
        sd = software_deployment_object.SoftwareDeployment.get_by_id(
350
 
            self.ctx, deployment_id)
351
 
        self.assertEqual('FAILED', sd.status)
352
 
        self.assertEqual(
353
 
            ('foo : bar, deploy_status_code : Deployment exited with '
354
 
             'non-zero status code: -1'),
355
 
            sd.status_reason)
356
 
        self.assertEqual({
357
 
            'deploy_status_code': -1,
358
 
            'foo': 'bar',
359
 
            'deploy_stderr': 'Its gone Pete Tong',
360
 
            'deploy_stdout': None
361
 
        }, sd.output_values)
362
 
        self.assertIsNotNone(sd.updated_at)
363
 
 
364
 
    def test_create_software_deployment(self):
365
 
        kwargs = {
366
 
            'group': 'Heat::Chef',
367
 
            'name': 'config_heat',
368
 
            'config': '...',
369
 
            'inputs': [{'name': 'mode'}],
370
 
            'outputs': [{'name': 'endpoint'}],
371
 
            'options': {}
372
 
        }
373
 
        config = self._create_software_config(**kwargs)
374
 
        config_id = config['id']
375
 
        kwargs = {
376
 
            'config_id': config_id,
377
 
            'input_values': {'mode': 'standalone'},
378
 
            'action': 'INIT',
379
 
            'status': 'COMPLETE',
380
 
            'status_reason': ''
381
 
        }
382
 
        deployment = self._create_software_deployment(**kwargs)
383
 
        deployment_id = deployment['id']
384
 
        deployment = self.engine.show_software_deployment(
385
 
            self.ctx, deployment_id)
386
 
        self.assertEqual(deployment_id, deployment['id'])
387
 
        self.assertEqual(kwargs['input_values'], deployment['input_values'])
388
 
 
389
 
    @mock.patch.object(service_software_config.SoftwareConfigService,
390
 
                       '_refresh_swift_software_deployment')
391
 
    def test_show_software_deployment_refresh(
392
 
            self, _refresh_swift_software_deployment):
393
 
        temp_url = ('http://192.0.2.1/v1/AUTH_a/b/c'
394
 
                    '?temp_url_sig=ctemp_url_expires=1234')
395
 
        config = self._create_software_config(inputs=[
396
 
            {
397
 
                'name': 'deploy_signal_transport',
398
 
                'type': 'String',
399
 
                'value': 'TEMP_URL_SIGNAL'
400
 
            }, {
401
 
                'name': 'deploy_signal_id',
402
 
                'type': 'String',
403
 
                'value': temp_url
404
 
            }
405
 
        ])
406
 
 
407
 
        deployment = self._create_software_deployment(
408
 
            status='IN_PROGRESS', config_id=config['id'])
409
 
 
410
 
        deployment_id = deployment['id']
411
 
        sd = software_deployment_object.SoftwareDeployment.get_by_id(
412
 
            self.ctx, deployment_id)
413
 
        _refresh_swift_software_deployment.return_value = sd
414
 
        self.assertEqual(
415
 
            deployment,
416
 
            self.engine.show_software_deployment(self.ctx, deployment_id))
417
 
        self.assertEqual(
418
 
            (self.ctx, sd, temp_url),
419
 
            _refresh_swift_software_deployment.call_args[0])
420
 
 
421
 
    def test_update_software_deployment_new_config(self):
422
 
 
423
 
        server_id = str(uuid.uuid4())
424
 
        mock_push = self.patchobject(self.engine.software_config,
425
 
                                     '_push_metadata_software_deployments')
426
 
 
427
 
        deployment = self._create_software_deployment(server_id=server_id)
428
 
        self.assertIsNotNone(deployment)
429
 
        deployment_id = deployment['id']
430
 
        deployment_action = deployment['action']
431
 
        self.assertEqual('INIT', deployment_action)
432
 
        config_id = deployment['config_id']
433
 
        self.assertIsNotNone(config_id)
434
 
        updated = self.engine.update_software_deployment(
435
 
            self.ctx, deployment_id=deployment_id, config_id=config_id,
436
 
            input_values={}, output_values={}, action='DEPLOY',
437
 
            status='WAITING', status_reason='', updated_at=None)
438
 
        self.assertIsNotNone(updated)
439
 
        self.assertEqual(config_id, updated['config_id'])
440
 
        self.assertEqual('DEPLOY', updated['action'])
441
 
        self.assertEqual('WAITING', updated['status'])
442
 
        self.assertEqual(2, mock_push.call_count)
443
 
 
444
 
    def test_update_software_deployment_status(self):
445
 
 
446
 
        server_id = str(uuid.uuid4())
447
 
        mock_push = self.patchobject(self.engine.software_config,
448
 
                                     '_push_metadata_software_deployments')
449
 
 
450
 
        deployment = self._create_software_deployment(server_id=server_id)
451
 
 
452
 
        self.assertIsNotNone(deployment)
453
 
        deployment_id = deployment['id']
454
 
        deployment_action = deployment['action']
455
 
        self.assertEqual('INIT', deployment_action)
456
 
        updated = self.engine.update_software_deployment(
457
 
            self.ctx, deployment_id=deployment_id, config_id=None,
458
 
            input_values=None, output_values={}, action='DEPLOY',
459
 
            status='WAITING', status_reason='', updated_at=None)
460
 
        self.assertIsNotNone(updated)
461
 
        self.assertEqual('DEPLOY', updated['action'])
462
 
        self.assertEqual('WAITING', updated['status'])
463
 
 
464
 
        sd = software_deployment_object.SoftwareDeployment.get_by_id(
465
 
            self.ctx, deployment_id)
466
 
        mock_push.assert_called_once_with(self.ctx, server_id, sd)
467
 
 
468
 
    def test_update_software_deployment_fields(self):
469
 
 
470
 
        deployment = self._create_software_deployment()
471
 
        deployment_id = deployment['id']
472
 
        config_id = deployment['config_id']
473
 
 
474
 
        def check_software_deployment_updated(**kwargs):
475
 
            values = {
476
 
                'config_id': None,
477
 
                'input_values': {},
478
 
                'output_values': {},
479
 
                'action': {},
480
 
                'status': 'WAITING',
481
 
                'status_reason': ''
482
 
            }
483
 
            values.update(kwargs)
484
 
            updated = self.engine.update_software_deployment(
485
 
                self.ctx, deployment_id, updated_at=None, **values)
486
 
            for key, value in six.iteritems(kwargs):
487
 
                self.assertEqual(value, updated[key])
488
 
 
489
 
        check_software_deployment_updated(config_id=config_id)
490
 
        check_software_deployment_updated(input_values={'foo': 'fooooo'})
491
 
        check_software_deployment_updated(output_values={'bar': 'baaaaa'})
492
 
        check_software_deployment_updated(action='DEPLOY')
493
 
        check_software_deployment_updated(status='COMPLETE')
494
 
        check_software_deployment_updated(status_reason='Done!')
495
 
 
496
 
    def test_delete_software_deployment(self):
497
 
        deployment_id = str(uuid.uuid4())
498
 
        ex = self.assertRaises(dispatcher.ExpectedException,
499
 
                               self.engine.delete_software_deployment,
500
 
                               self.ctx, deployment_id)
501
 
        self.assertEqual(exception.NotFound, ex.exc_info[0])
502
 
 
503
 
        deployment = self._create_software_deployment()
504
 
        self.assertIsNotNone(deployment)
505
 
        deployment_id = deployment['id']
506
 
        deployments = self.engine.list_software_deployments(
507
 
            self.ctx, server_id=None)
508
 
        deployment_ids = [x['id'] for x in deployments]
509
 
        self.assertIn(deployment_id, deployment_ids)
510
 
        self.engine.delete_software_deployment(self.ctx, deployment_id)
511
 
        deployments = self.engine.list_software_deployments(
512
 
            self.ctx, server_id=None)
513
 
        deployment_ids = [x['id'] for x in deployments]
514
 
        self.assertNotIn(deployment_id, deployment_ids)
515
 
 
516
 
    @mock.patch.object(service_software_config.SoftwareConfigService,
517
 
                       'metadata_software_deployments')
518
 
    @mock.patch.object(service_software_config.resource_object.Resource,
519
 
                       'get_by_physical_resource_id')
520
 
    @mock.patch.object(service_software_config.requests, 'put')
521
 
    def test_push_metadata_software_deployments(self, put, res_get, md_sd):
522
 
        rs = mock.Mock()
523
 
        rs.rsrc_metadata = {'original': 'metadata'}
524
 
        rs.data = []
525
 
        res_get.return_value = rs
526
 
 
527
 
        deployments = {'deploy': 'this'}
528
 
        md_sd.return_value = deployments
529
 
 
530
 
        result_metadata = {
531
 
            'original': 'metadata',
532
 
            'deployments': {'deploy': 'this'}
533
 
        }
534
 
 
535
 
        self.engine.software_config._push_metadata_software_deployments(
536
 
            self.ctx, '1234', None)
537
 
        rs.update_and_save.assert_called_once_with(
538
 
            {'rsrc_metadata': result_metadata})
539
 
        put.side_effect = Exception('Unexpected requests.put')
540
 
 
541
 
    @mock.patch.object(service_software_config.SoftwareConfigService,
542
 
                       'metadata_software_deployments')
543
 
    @mock.patch.object(service_software_config.resource_object.Resource,
544
 
                       'get_by_physical_resource_id')
545
 
    @mock.patch.object(service_software_config.requests, 'put')
546
 
    def test_push_metadata_software_deployments_temp_url(
547
 
            self, put, res_get, md_sd):
548
 
        rs = mock.Mock()
549
 
        rs.rsrc_metadata = {'original': 'metadata'}
550
 
        rd = mock.Mock()
551
 
        rd.key = 'metadata_put_url'
552
 
        rd.value = 'http://192.168.2.2/foo/bar'
553
 
        rs.data = [rd]
554
 
        res_get.return_value = rs
555
 
 
556
 
        deployments = {'deploy': 'this'}
557
 
        md_sd.return_value = deployments
558
 
 
559
 
        result_metadata = {
560
 
            'original': 'metadata',
561
 
            'deployments': {'deploy': 'this'}
562
 
        }
563
 
 
564
 
        self.engine.software_config._push_metadata_software_deployments(
565
 
            self.ctx, '1234', None)
566
 
        rs.update_and_save.assert_called_once_with(
567
 
            {'rsrc_metadata': result_metadata})
568
 
 
569
 
        put.assert_called_once_with(
570
 
            'http://192.168.2.2/foo/bar', json.dumps(result_metadata))
571
 
 
572
 
    @mock.patch.object(service_software_config.SoftwareConfigService,
573
 
                       'metadata_software_deployments')
574
 
    @mock.patch.object(service_software_config.resource_object.Resource,
575
 
                       'get_by_physical_resource_id')
576
 
    @mock.patch.object(zaqar.ZaqarClientPlugin, 'create_for_tenant')
577
 
    def test_push_metadata_software_deployments_queue(
578
 
            self, plugin, res_get, md_sd):
579
 
        rs = mock.Mock()
580
 
        rs.rsrc_metadata = {'original': 'metadata'}
581
 
        rd = mock.Mock()
582
 
        rd.key = 'metadata_queue_id'
583
 
        rd.value = '6789'
584
 
        rs.data = [rd]
585
 
        res_get.return_value = rs
586
 
        sd = mock.Mock()
587
 
        sd.stack_user_project_id = 'project1'
588
 
        queue = mock.Mock()
589
 
        zaqar_client = mock.Mock()
590
 
        plugin.return_value = zaqar_client
591
 
        zaqar_client.queue.return_value = queue
592
 
 
593
 
        deployments = {'deploy': 'this'}
594
 
        md_sd.return_value = deployments
595
 
 
596
 
        result_metadata = {
597
 
            'original': 'metadata',
598
 
            'deployments': {'deploy': 'this'}
599
 
        }
600
 
 
601
 
        self.engine.software_config._push_metadata_software_deployments(
602
 
            self.ctx, '1234', sd)
603
 
        rs.update_and_save.assert_called_once_with(
604
 
            {'rsrc_metadata': result_metadata})
605
 
 
606
 
        plugin.assert_called_once_with('project1')
607
 
        zaqar_client.queue.assert_called_once_with('6789')
608
 
        queue.post.assert_called_once_with(
609
 
            {'body': result_metadata, 'ttl': 3600})
610
 
 
611
 
    @mock.patch.object(service_software_config.SoftwareConfigService,
612
 
                       'signal_software_deployment')
613
 
    @mock.patch.object(swift.SwiftClientPlugin, '_create')
614
 
    def test_refresh_swift_software_deployment(self, scc, ssd):
615
 
        temp_url = ('http://192.0.2.1/v1/AUTH_a/b/c'
616
 
                    '?temp_url_sig=ctemp_url_expires=1234')
617
 
        container = 'b'
618
 
        object_name = 'c'
619
 
 
620
 
        config = self._create_software_config(inputs=[
621
 
            {
622
 
                'name': 'deploy_signal_transport',
623
 
                'type': 'String',
624
 
                'value': 'TEMP_URL_SIGNAL'
625
 
            }, {
626
 
                'name': 'deploy_signal_id',
627
 
                'type': 'String',
628
 
                'value': temp_url
629
 
            }
630
 
        ])
631
 
 
632
 
        timeutils.set_time_override(
633
 
            datetime.datetime(2013, 1, 23, 22, 48, 5, 0))
634
 
        self.addCleanup(timeutils.clear_time_override)
635
 
        now = timeutils.utcnow()
636
 
        then = now - datetime.timedelta(0, 60)
637
 
 
638
 
        last_modified_1 = 'Wed, 23 Jan 2013 22:47:05 GMT'
639
 
        last_modified_2 = 'Wed, 23 Jan 2013 22:48:05 GMT'
640
 
 
641
 
        sc = mock.MagicMock()
642
 
        headers = {
643
 
            'last-modified': last_modified_1
644
 
        }
645
 
        sc.head_object.return_value = headers
646
 
        sc.get_object.return_value = (headers, '{"foo": "bar"}')
647
 
        scc.return_value = sc
648
 
 
649
 
        deployment = self._create_software_deployment(
650
 
            status='IN_PROGRESS', config_id=config['id'])
651
 
 
652
 
        deployment_id = six.text_type(deployment['id'])
653
 
        sd = software_deployment_object.SoftwareDeployment.get_by_id(
654
 
            self.ctx, deployment_id)
655
 
 
656
 
        # poll with missing object
657
 
        swift_exc = swift.SwiftClientPlugin.exceptions_module
658
 
        sc.head_object.side_effect = swift_exc.ClientException(
659
 
            'Not found', http_status=404)
660
 
 
661
 
        self.assertEqual(
662
 
            sd,
663
 
            self.engine.software_config._refresh_swift_software_deployment(
664
 
                self.ctx, sd, temp_url))
665
 
        sc.head_object.assert_called_once_with(container, object_name)
666
 
        # no call to get_object or signal_last_modified
667
 
        self.assertEqual([], sc.get_object.mock_calls)
668
 
        self.assertEqual([], ssd.mock_calls)
669
 
 
670
 
        # poll with other error
671
 
        sc.head_object.side_effect = swift_exc.ClientException(
672
 
            'Ouch', http_status=409)
673
 
        self.assertRaises(
674
 
            swift_exc.ClientException,
675
 
            self.engine.software_config._refresh_swift_software_deployment,
676
 
            self.ctx,
677
 
            sd,
678
 
            temp_url)
679
 
        # no call to get_object or signal_last_modified
680
 
        self.assertEqual([], sc.get_object.mock_calls)
681
 
        self.assertEqual([], ssd.mock_calls)
682
 
        sc.head_object.side_effect = None
683
 
 
684
 
        # first poll populates data signal_last_modified
685
 
        self.engine.software_config._refresh_swift_software_deployment(
686
 
            self.ctx, sd, temp_url)
687
 
        sc.head_object.assert_called_with(container, object_name)
688
 
        sc.get_object.assert_called_once_with(container, object_name)
689
 
        # signal_software_deployment called with signal
690
 
        ssd.assert_called_once_with(self.ctx, deployment_id, {u"foo": u"bar"},
691
 
                                    then.isoformat())
692
 
 
693
 
        # second poll updated_at populated with first poll last-modified
694
 
        software_deployment_object.SoftwareDeployment.update_by_id(
695
 
            self.ctx, deployment_id, {'updated_at': then})
696
 
        sd = software_deployment_object.SoftwareDeployment.get_by_id(
697
 
            self.ctx, deployment_id)
698
 
        self.assertEqual(then, sd.updated_at)
699
 
        self.engine.software_config._refresh_swift_software_deployment(
700
 
            self.ctx, sd, temp_url)
701
 
        sc.get_object.assert_called_once_with(container, object_name)
702
 
        # signal_software_deployment has not been called again
703
 
        ssd.assert_called_once_with(self.ctx, deployment_id, {"foo": "bar"},
704
 
                                    then.isoformat())
705
 
 
706
 
        # third poll last-modified changed, new signal
707
 
        headers['last-modified'] = last_modified_2
708
 
        sc.head_object.return_value = headers
709
 
        sc.get_object.return_value = (headers, '{"bar": "baz"}')
710
 
        self.engine.software_config._refresh_swift_software_deployment(
711
 
            self.ctx, sd, temp_url)
712
 
 
713
 
        # two calls to signal_software_deployment, for then and now
714
 
        self.assertEqual(2, len(ssd.mock_calls))
715
 
        ssd.assert_called_with(self.ctx, deployment_id, {"bar": "baz"},
716
 
                               now.isoformat())
717
 
 
718
 
        # four polls result in only two signals, for then and now
719
 
        software_deployment_object.SoftwareDeployment.update_by_id(
720
 
            self.ctx, deployment_id, {'updated_at': now})
721
 
        sd = software_deployment_object.SoftwareDeployment.get_by_id(
722
 
            self.ctx, deployment_id)
723
 
        self.engine.software_config._refresh_swift_software_deployment(
724
 
            self.ctx, sd, temp_url)
725
 
        self.assertEqual(2, len(ssd.mock_calls))
726
 
 
727
 
    @mock.patch.object(service_software_config.SoftwareConfigService,
728
 
                       'signal_software_deployment')
729
 
    @mock.patch.object(zaqar.ZaqarClientPlugin, 'create_for_tenant')
730
 
    def test_refresh_zaqar_software_deployment(self, plugin, ssd):
731
 
        config = self._create_software_config(inputs=[
732
 
            {
733
 
                'name': 'deploy_signal_transport',
734
 
                'type': 'String',
735
 
                'value': 'ZAQAR_SIGNAL'
736
 
            }, {
737
 
                'name': 'deploy_queue_id',
738
 
                'type': 'String',
739
 
                'value': '6789'
740
 
            }
741
 
        ])
742
 
 
743
 
        queue = mock.Mock()
744
 
        zaqar_client = mock.Mock()
745
 
        plugin.return_value = zaqar_client
746
 
        zaqar_client.queue.return_value = queue
747
 
        queue.pop.return_value = [mock.Mock(body='ok')]
748
 
 
749
 
        deployment = self._create_software_deployment(
750
 
            status='IN_PROGRESS', config_id=config['id'])
751
 
 
752
 
        deployment_id = deployment['id']
753
 
        self.assertEqual(
754
 
            deployment,
755
 
            self.engine.show_software_deployment(self.ctx, deployment_id))
756
 
 
757
 
        zaqar_client.queue.assert_called_once_with('6789')
758
 
        queue.pop.assert_called_once_with()
759
 
        ssd.assert_called_once_with(self.ctx, deployment_id, 'ok', None)