~ubuntu-branches/debian/stretch/waagent/stretch

« back to all changes in this revision

Viewing changes to tests/ga/test_extension.py

  • Committer: Package Import Robot
  • Author(s): Bastian Blank
  • Date: 2016-08-24 16:48:22 UTC
  • mfrom: (1.2.5)
  • Revision ID: package-import@ubuntu.com-20160824164822-vdf8m5xy5gycm1cz
Tags: 2.1.6-1
New upstream version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2014 Microsoft Corporation
 
2
#
 
3
# Licensed under the Apache License, Version 2.0 (the "License");
 
4
# you may not use this file except in compliance with the License.
 
5
# You may obtain a copy of the License at
 
6
#
 
7
#     http://www.apache.org/licenses/LICENSE-2.0
 
8
#
 
9
# Unless required by applicable law or agreed to in writing, software
 
10
# distributed under the License is distributed on an "AS IS" BASIS,
 
11
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
12
# See the License for the specific language governing permissions and
 
13
# limitations under the License.
 
14
#
 
15
# Requires Python 2.4+ and Openssl 1.0+
 
16
#
 
17
 
 
18
import azurelinuxagent.common.utils.fileutil as fileutil
 
19
 
 
20
from tests.protocol.mockwiredata import *
 
21
 
 
22
from azurelinuxagent.common.exception import *
 
23
from azurelinuxagent.common.protocol import get_protocol_util
 
24
from azurelinuxagent.common.protocol.restapi import ExtHandlerStatus, \
 
25
                                                    ExtensionStatus, \
 
26
                                                    ExtensionSubStatus, \
 
27
                                                    Extension, \
 
28
                                                    VMStatus, ExtHandler, \
 
29
                                                    get_properties
 
30
from azurelinuxagent.ga.exthandlers import *
 
31
from azurelinuxagent.common.protocol.wire import WireProtocol
 
32
 
 
33
class TestHandlerStateMigration(AgentTestCase):
 
34
    def setUp(self):
 
35
        AgentTestCase.setUp(self)
 
36
 
 
37
        handler_name = "Not.A.Real.Extension"
 
38
        handler_version = "1.2.3"
 
39
 
 
40
        self.ext_handler = ExtHandler(handler_name)
 
41
        self.ext_handler.properties.version = handler_version
 
42
        self.ext_handler_i = ExtHandlerInstance(self.ext_handler, "dummy protocol")
 
43
 
 
44
        self.handler_state = "Enabled"
 
45
        self.handler_status = ExtHandlerStatus(
 
46
            name=handler_name,
 
47
            version=handler_version,
 
48
            status="Ready",
 
49
            message="Uninteresting message")
 
50
        return
 
51
 
 
52
    def _prepare_handler_state(self):
 
53
        handler_state_path = os.path.join(
 
54
                                self.tmp_dir,
 
55
                                "handler_state",
 
56
                                self.ext_handler_i.get_full_name())
 
57
        os.makedirs(handler_state_path)
 
58
        fileutil.write_file(
 
59
            os.path.join(handler_state_path, "state"),
 
60
            self.handler_state)
 
61
        fileutil.write_file(
 
62
            os.path.join(handler_state_path, "status"),
 
63
            json.dumps(get_properties(self.handler_status)))
 
64
        return
 
65
 
 
66
    def _prepare_handler_config(self):
 
67
        handler_config_path = os.path.join(
 
68
                                self.tmp_dir,
 
69
                                self.ext_handler_i.get_full_name(),
 
70
                                "config")
 
71
        os.makedirs(handler_config_path)
 
72
        return
 
73
 
 
74
    def test_migration_migrates(self):
 
75
        self._prepare_handler_state()
 
76
        self._prepare_handler_config()
 
77
 
 
78
        migrate_handler_state()
 
79
 
 
80
        self.assertEquals(self.ext_handler_i.get_handler_state(), self.handler_state)
 
81
        self.assertEquals(
 
82
            self.ext_handler_i.get_handler_status().status,
 
83
            self.handler_status.status)
 
84
        return
 
85
 
 
86
    def test_migration_skips_if_empty(self):
 
87
        self._prepare_handler_config()
 
88
 
 
89
        migrate_handler_state()
 
90
 
 
91
        self.assertFalse(
 
92
            os.path.isfile(os.path.join(self.ext_handler_i.get_conf_dir(), "HandlerState")))
 
93
        self.assertFalse(
 
94
            os.path.isfile(os.path.join(self.ext_handler_i.get_conf_dir(), "HandlerStatus")))
 
95
        return
 
96
 
 
97
    def test_migration_cleans_up(self):
 
98
        self._prepare_handler_state()
 
99
        self._prepare_handler_config()
 
100
 
 
101
        migrate_handler_state()
 
102
 
 
103
        self.assertFalse(os.path.isdir(os.path.join(conf.get_lib_dir(), "handler_state")))
 
104
        return
 
105
 
 
106
    def test_migration_does_not_overwrite(self):
 
107
        self._prepare_handler_state()
 
108
        self._prepare_handler_config()
 
109
 
 
110
        state = "Installed"
 
111
        status = "NotReady"
 
112
        code = 1
 
113
        message = "A message"
 
114
        self.assertNotEquals(state, self.handler_state)
 
115
        self.assertNotEquals(status, self.handler_status.status)
 
116
        self.assertNotEquals(code, self.handler_status.code)
 
117
        self.assertNotEquals(message, self.handler_status.message)
 
118
 
 
119
        self.ext_handler_i.set_handler_state(state)
 
120
        self.ext_handler_i.set_handler_status(status=status, code=code, message=message)
 
121
 
 
122
        migrate_handler_state()
 
123
 
 
124
        self.assertEquals(self.ext_handler_i.get_handler_state(), state)
 
125
        handler_status = self.ext_handler_i.get_handler_status()
 
126
        self.assertEquals(handler_status.status, status)
 
127
        self.assertEquals(handler_status.code, code)
 
128
        self.assertEquals(handler_status.message, message)
 
129
        return
 
130
 
 
131
    @patch("shutil.move", side_effect=Exception)
 
132
    def test_migration_ignores_move_errors(self, shutil_mock):
 
133
        self._prepare_handler_state()
 
134
        self._prepare_handler_config()
 
135
 
 
136
        try:
 
137
            migrate_handler_state()
 
138
        except Exception as e:
 
139
            self.assertTrue(False, "Unexpected exception: {0}".format(str(e)))
 
140
        return
 
141
 
 
142
    @patch("shutil.rmtree", side_effect=Exception)
 
143
    def test_migration_ignores_tree_remove_errors(self, shutil_mock):
 
144
        self._prepare_handler_state()
 
145
        self._prepare_handler_config()
 
146
 
 
147
        try:
 
148
            migrate_handler_state()
 
149
        except Exception as e:
 
150
            self.assertTrue(False, "Unexpected exception: {0}".format(str(e)))
 
151
        return
 
152
 
 
153
@patch("azurelinuxagent.common.protocol.wire.CryptUtil")
 
154
@patch("azurelinuxagent.common.utils.restutil.http_get")
 
155
class TestExtension(AgentTestCase):
 
156
 
 
157
    def _assert_handler_status(self, report_vm_status, expected_status, 
 
158
                               expected_ext_count, version):
 
159
        self.assertTrue(report_vm_status.called)
 
160
        args, kw = report_vm_status.call_args
 
161
        vm_status = args[0]
 
162
        self.assertNotEquals(0, len(vm_status.vmAgent.extensionHandlers))
 
163
        handler_status = vm_status.vmAgent.extensionHandlers[0]
 
164
        self.assertEquals(expected_status, handler_status.status)
 
165
        self.assertEquals("OSTCExtensions.ExampleHandlerLinux", 
 
166
                          handler_status.name)
 
167
        self.assertEquals(version, handler_status.version)
 
168
        self.assertEquals(expected_ext_count, len(handler_status.extensions))
 
169
        return
 
170
    
 
171
    def _assert_no_handler_status(self, report_vm_status):
 
172
        self.assertTrue(report_vm_status.called)
 
173
        args, kw = report_vm_status.call_args
 
174
        vm_status = args[0]
 
175
        self.assertEquals(0, len(vm_status.vmAgent.extensionHandlers))
 
176
        return
 
177
 
 
178
    def _create_mock(self, test_data, mock_http_get, MockCryptUtil):
 
179
        """Test enable/disable/uninstall of an extension"""
 
180
        handler = get_exthandlers_handler()
 
181
 
 
182
        #Mock protocol to return test data
 
183
        mock_http_get.side_effect = test_data.mock_http_get
 
184
        MockCryptUtil.side_effect = test_data.mock_crypt_util
 
185
 
 
186
        protocol = WireProtocol("foo.bar")
 
187
        protocol.detect()
 
188
        protocol.report_ext_status = MagicMock()
 
189
        protocol.report_vm_status = MagicMock()
 
190
 
 
191
        handler.protocol_util.get_protocol = Mock(return_value=protocol)
 
192
        return handler, protocol
 
193
        
 
194
    def test_ext_handler(self, *args):
 
195
        test_data = WireProtocolData(DATA_FILE)
 
196
        exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
197
 
 
198
        #Test enable scenario. 
 
199
        exthandlers_handler.run()
 
200
        self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0")
 
201
        self._assert_ext_status(protocol.report_ext_status, "success", 0)
 
202
 
 
203
        #Test goal state not changed
 
204
        exthandlers_handler.run()
 
205
        self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0")
 
206
 
 
207
        #Test goal state changed
 
208
        test_data.goal_state = test_data.goal_state.replace("<Incarnation>1<",
 
209
                                                            "<Incarnation>2<")
 
210
        test_data.ext_conf = test_data.ext_conf.replace("seqNo=\"0\"", 
 
211
                                                        "seqNo=\"1\"")
 
212
        exthandlers_handler.run()
 
213
        self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0")
 
214
        self._assert_ext_status(protocol.report_ext_status, "success", 1)
 
215
        
 
216
        #Test upgrade
 
217
        test_data.goal_state = test_data.goal_state.replace("<Incarnation>2<",
 
218
                                                            "<Incarnation>3<")
 
219
        test_data.ext_conf = test_data.ext_conf.replace("1.0.0", "1.1.0")
 
220
        test_data.ext_conf = test_data.ext_conf.replace("seqNo=\"1\"", 
 
221
                                                        "seqNo=\"2\"")
 
222
        exthandlers_handler.run()
 
223
        self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.1.0")
 
224
        self._assert_ext_status(protocol.report_ext_status, "success", 2)
 
225
 
 
226
        #Test disable
 
227
        test_data.goal_state = test_data.goal_state.replace("<Incarnation>3<",
 
228
                                                            "<Incarnation>4<")
 
229
        test_data.ext_conf = test_data.ext_conf.replace("enabled", "disabled")
 
230
        exthandlers_handler.run()
 
231
        self._assert_handler_status(protocol.report_vm_status, "NotReady", 
 
232
                                    1, "1.1.0")
 
233
 
 
234
        #Test uninstall
 
235
        test_data.goal_state = test_data.goal_state.replace("<Incarnation>4<",
 
236
                                                            "<Incarnation>5<")
 
237
        test_data.ext_conf = test_data.ext_conf.replace("disabled", "uninstall")
 
238
        exthandlers_handler.run()
 
239
        self._assert_no_handler_status(protocol.report_vm_status)
 
240
 
 
241
        #Test uninstall again!
 
242
        test_data.goal_state = test_data.goal_state.replace("<Incarnation>5<",
 
243
                                                            "<Incarnation>6<")
 
244
        exthandlers_handler.run()
 
245
        self._assert_no_handler_status(protocol.report_vm_status)
 
246
 
 
247
    def test_ext_handler_no_settings(self, *args):
 
248
        test_data = WireProtocolData(DATA_FILE_EXT_NO_SETTINGS)
 
249
        exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
250
 
 
251
        exthandlers_handler.run()
 
252
        self._assert_handler_status(protocol.report_vm_status, "Ready", 0, "1.0.0")
 
253
 
 
254
    def test_ext_handler_no_public_settings(self, *args):
 
255
        test_data = WireProtocolData(DATA_FILE_EXT_NO_PUBLIC)
 
256
        exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
257
 
 
258
        exthandlers_handler.run()
 
259
        self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0")
 
260
 
 
261
    def test_ext_handler_no_ext(self, *args):
 
262
        test_data = WireProtocolData(DATA_FILE_NO_EXT)
 
263
        exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
264
 
 
265
        #Assert no extension handler status
 
266
        exthandlers_handler.run()
 
267
        self._assert_no_handler_status(protocol.report_vm_status)
 
268
    
 
269
    @patch('azurelinuxagent.ga.exthandlers.add_event')
 
270
    def test_ext_handler_download_failure(self, mock_add_event, *args):
 
271
        test_data = WireProtocolData(DATA_FILE)
 
272
        exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
273
        protocol.download_ext_handler_pkg = Mock(side_effect=ProtocolError)
 
274
 
 
275
        exthandlers_handler.run()
 
276
        args, kw = mock_add_event.call_args
 
277
        self.assertEquals(False, kw['is_success'])
 
278
        self.assertEquals("OSTCExtensions.ExampleHandlerLinux", kw['name'])
 
279
        self.assertEquals("Download", kw['op'])
 
280
 
 
281
    @patch('azurelinuxagent.ga.exthandlers.fileutil')
 
282
    def test_ext_handler_io_error(self, mock_fileutil, *args):
 
283
        test_data = WireProtocolData(DATA_FILE)
 
284
        exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
285
    
 
286
        mock_fileutil.write_file.return_value = IOError("Mock IO Error")
 
287
        exthandlers_handler.run()
 
288
 
 
289
    def _assert_ext_status(self, report_ext_status, expected_status, 
 
290
                           expected_seq_no):
 
291
        self.assertTrue(report_ext_status.called)
 
292
        args, kw = report_ext_status.call_args
 
293
        ext_status = args[-1]
 
294
        self.assertEquals(expected_status, ext_status.status)
 
295
        self.assertEquals(expected_seq_no, ext_status.sequenceNumber)
 
296
 
 
297
    def test_ext_handler_no_reporting_status(self, *args):
 
298
        test_data = WireProtocolData(DATA_FILE)
 
299
        exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
300
        exthandlers_handler.run()
 
301
        self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0")
 
302
 
 
303
        #Remove status file and re-run collecting extension status
 
304
        status_file = os.path.join(self.tmp_dir, 
 
305
                                   "OSTCExtensions.ExampleHandlerLinux-1.0.0",
 
306
                                   "status", "0.status")
 
307
        self.assertTrue(os.path.isfile(status_file))
 
308
        os.remove(status_file)
 
309
 
 
310
        exthandlers_handler.run()
 
311
        self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0")
 
312
        self._assert_ext_status(protocol.report_ext_status, "error", 0)
 
313
 
 
314
    def test_ext_handler_version_decide_autoupgrade_internalversion(self, *args):
 
315
        for internal in [False, True]:
 
316
            for autoupgrade in [False, True]:
 
317
                if internal:
 
318
                    config_version = '1.2.0'
 
319
                    decision_version = '1.2.0'
 
320
                    if autoupgrade:
 
321
                        datafile = DATA_FILE_EXT_AUTOUPGRADE_INTERNALVERSION
 
322
                    else:
 
323
                        datafile = DATA_FILE_EXT_INTERNALVERSION
 
324
                else:
 
325
                    config_version = '1.0.0'
 
326
                    if autoupgrade:
 
327
                        datafile = DATA_FILE_EXT_AUTOUPGRADE
 
328
                        decision_version = '1.1.0'
 
329
                    else:
 
330
                        datafile = DATA_FILE
 
331
                        decision_version = '1.0.0'
 
332
 
 
333
                _, protocol = self._create_mock(WireProtocolData(datafile), *args)
 
334
                ext_handlers, _ = protocol.get_ext_handlers()
 
335
                self.assertEqual(1, len(ext_handlers.extHandlers))
 
336
                ext_handler = ext_handlers.extHandlers[0]
 
337
                self.assertEqual('OSTCExtensions.ExampleHandlerLinux', ext_handler.name)
 
338
                self.assertEqual(config_version, ext_handler.properties.version, "config version.")
 
339
                ExtHandlerInstance(ext_handler, protocol).decide_version()
 
340
                self.assertEqual(decision_version, ext_handler.properties.version, "decision version.")
 
341
 
 
342
    def test_ext_handler_version_decide_between_minor_versions(self, *args):
 
343
        """
 
344
        Using v2.x~v4.x for unit testing
 
345
        Available versions via manifest XML (I stands for internal):
 
346
        2.0.0, 2.1.0, 2.1.1, 2.2.0, 2.3.0(I), 2.4.0(I), 3.0, 3.1, 4.0.0.0, 4.0.0.1, 4.1.0.0
 
347
        See tests/data/wire/manifest.xml for possible versions
 
348
        """
 
349
 
 
350
        # (installed_version, config_version, exptected_version, autoupgrade_expected_version)
 
351
        cases = [
 
352
            (None,  '2.0',     '2.0.0',    '2.2.0'),
 
353
            (None,  '2.0.0',   '2.0.0',    '2.2.0'),
 
354
            ('1.0', '1.0.0',   '1.0.0',    '1.1.0'),
 
355
            (None,  '2.1.0',   '2.1.1',    '2.2.0'),
 
356
            (None,  '2.2.0',   '2.2.0',    '2.2.0'),
 
357
            (None,  '2.3.0',   '2.3.0',    '2.3.0'),
 
358
            (None,  '2.4.0',   '2.4.0',    '2.4.0'),
 
359
            (None,  '3.0',     '3.0',      '3.1'),
 
360
            (None,  '4.0',     '4.0.0.1',  '4.1.0.0'),
 
361
        ]
 
362
 
 
363
        _, protocol = self._create_mock(WireProtocolData(DATA_FILE), *args)
 
364
        version_uri = Mock()
 
365
        version_uri.uri = 'http://some/Microsoft.OSTCExtensions_ExampleHandlerLinux_asiaeast_manifest.xml'
 
366
 
 
367
        for (installed_version, config_version, expected_version, autoupgrade_expected_version) in cases:
 
368
            ext_handler = Mock()
 
369
            ext_handler.properties = Mock()
 
370
            ext_handler.name = 'OSTCExtensions.ExampleHandlerLinux'
 
371
            ext_handler.versionUris = [version_uri]
 
372
            ext_handler.properties.version = config_version
 
373
            
 
374
            ext_handler_instance = ExtHandlerInstance(ext_handler, protocol)
 
375
            ext_handler_instance.get_installed_version = Mock(return_value=installed_version)
 
376
 
 
377
            ext_handler_instance.decide_version()
 
378
            self.assertEqual(expected_version, ext_handler.properties.version)
 
379
 
 
380
            ext_handler.properties.version = config_version
 
381
            ext_handler.properties.upgradePolicy = 'auto'
 
382
 
 
383
            ext_handler_instance = ExtHandlerInstance(ext_handler, protocol)
 
384
            ext_handler_instance.get_installed_version = Mock(return_value=installed_version)
 
385
 
 
386
            ext_handler_instance.decide_version()
 
387
            self.assertEqual(autoupgrade_expected_version, ext_handler.properties.version)
 
388
 
 
389
 
 
390
if __name__ == '__main__':
 
391
    unittest.main()
 
392