Esempio n. 1
0
    def test_validate_http_request(self):
        """Validate correct set of data is sent to HostGAPlugin when reporting VM status"""

        wire_protocol_client = wire.WireProtocol(wireserver_url).client
        test_goal_state = wire.GoalState(WireProtocolData(DATA_FILE).goal_state)

        status_blob = wire_protocol_client.status_blob
        status_blob.data = faux_status
        status_blob.vm_status = restapi.VMStatus(message="Ready", status="Ready")

        exp_method = 'PUT'
        exp_url = hostplugin_status_url
        exp_data = self._hostplugin_data(
                        status_blob.get_block_blob_headers(len(faux_status)),
                        bytearray(faux_status, encoding='utf-8'))

        with patch.object(restutil, "http_request") as patch_http:
            patch_http.return_value = Mock(status=httpclient.OK)

            wire_protocol_client.get_goal_state = Mock(return_value=test_goal_state)
            plugin = wire_protocol_client.get_host_plugin()

            with patch.object(plugin, 'get_api_versions') as patch_api:
                patch_api.return_value = API_VERSION
                plugin.put_vm_status(status_blob, sas_url, block_blob_type)

                self.assertTrue(patch_http.call_count == 1)
                self._validate_hostplugin_args(
                    patch_http.call_args_list[0],
                    test_goal_state,
                    exp_method, exp_url, exp_data)
Esempio n. 2
0
    def test_validate_get_extension_artifacts(self):
        test_goal_state = wire.GoalState(
            WireProtocolData(DATA_FILE).goal_state)
        expected_url = hostplugin.URI_FORMAT_GET_EXTENSION_ARTIFACT.format(
            wireserver_url, hostplugin.HOST_PLUGIN_PORT)
        expected_headers = {
            'x-ms-version': '2015-09-01',
            "x-ms-containerid": test_goal_state.container_id,
            "x-ms-host-config-name": test_goal_state.role_config_name,
            "x-ms-artifact-location": sas_url
        }

        host_client = wire.HostPluginProtocol(wireserver_url,
                                              test_goal_state.container_id,
                                              test_goal_state.role_config_name)
        self.assertFalse(host_client.is_initialized)
        self.assertTrue(host_client.api_versions is None)
        self.assertTrue(host_client.health_service is not None)

        with patch.object(wire.HostPluginProtocol,
                          "get_api_versions",
                          return_value=api_versions) as patch_get:
            actual_url, actual_headers = host_client.get_artifact_request(
                sas_url)
            self.assertTrue(host_client.is_initialized)
            self.assertFalse(host_client.api_versions is None)
            self.assertEqual(expected_url, actual_url)
            for k in expected_headers:
                self.assertTrue(k in actual_headers)
                self.assertEqual(expected_headers[k], actual_headers[k])
Esempio n. 3
0
    def test_validate_http_request(self):
        """Validate correct set of data is sent to HostGAPlugin when reporting VM status"""
        from azurelinuxagent.common.protocol.hostplugin import API_VERSION
        from azurelinuxagent.common.utils import restutil
        exp_method = 'PUT'
        exp_url = 'http://{0}:32526/status'.format(wireserver_url)
        exp_data = '{"content": "eyJkdW1teSI6ICJkYXRhIn0=", "headers": [{"headerName": ' \
                   '"x-ms-version", "headerValue": "2014-02-14"}, ' \
                   '{"headerName": "x-ms-blob-type", "headerValue": null}], ' \
                   '"requestUri": "http://sas_url"}'
        test_goal_state = wire.GoalState(
            WireProtocolData(DATA_FILE).goal_state)

        with patch.object(restutil, "http_request") as patch_http:
            wire_protocol_client = wire.WireProtocol(wireserver_url).client
            wire_protocol_client.get_goal_state = Mock(
                return_value=test_goal_state)
            plugin = wire_protocol_client.get_host_plugin()
            blob = wire_protocol_client.status_blob
            blob.vm_status = restapi.VMStatus()
            blob.data = '{"dummy": "data"}'
            with patch.object(plugin, 'get_api_versions') as patch_api:
                patch_api.return_value = API_VERSION
                plugin.put_vm_status(blob, sas_url)
                self.assertTrue(patch_http.call_count == 1)
                self.assertTrue(patch_http.call_args[0][0] == exp_method)
                self.assertTrue(patch_http.call_args[0][1] == exp_url)
                self.assertTrue(patch_http.call_args[0][2] == exp_data)

                # Assert headers
                headers = patch_http.call_args[1]['headers']
                self.assertEqual(headers['x-ms-containerid'],
                                 test_goal_state.container_id)
                self.assertEqual(headers['x-ms-host-config-name'],
                                 test_goal_state.role_instance_config_name)
Esempio n. 4
0
    def test_validate_block_blob(self):
        """Validate correct set of data is sent to HostGAPlugin when reporting VM status"""
        wire_protocol_client = wire.WireProtocol(wireserver_url).client
        test_goal_state = wire.GoalState(WireProtocolData(DATA_FILE).goal_state)

        host_client = wire.HostPluginProtocol(wireserver_url,
                                              test_goal_state.container_id,
                                              test_goal_state.role_config_name)
        self.assertFalse(host_client.is_initialized)
        self.assertTrue(host_client.api_versions is None)

        status_blob = wire_protocol_client.status_blob
        status_blob.data = faux_status
        status_blob.type = block_blob_type
        status_blob.vm_status = restapi.VMStatus(message="Ready", status="Ready")

        exp_method = 'PUT'
        exp_url = hostplugin_status_url
        exp_data = self._hostplugin_data(
                        status_blob.get_block_blob_headers(len(faux_status)),
                        bytearray(faux_status, encoding='utf-8'))

        with patch.object(restutil, "http_request") as patch_http:
            patch_http.return_value = Mock(status=httpclient.OK)

            with patch.object(wire.HostPluginProtocol,
                          "get_api_versions") as patch_get:
                patch_get.return_value = api_versions
                host_client.put_vm_status(status_blob, sas_url)

                self.assertTrue(patch_http.call_count == 1)
                self._validate_hostplugin_args(
                    patch_http.call_args_list[0],
                    test_goal_state,
                    exp_method, exp_url, exp_data)
Esempio n. 5
0
 def test_fallback_failure(self):
     """
     Validate that when host plugin fails, the default channel is reset
     """
     test_goal_state = wire.GoalState(WireProtocolData(DATA_FILE).goal_state)
     status = restapi.VMStatus(status="Ready",
                               message="Guest Agent is running")
     wire.HostPluginProtocol.set_default_channel(False)
     with patch.object(wire.HostPluginProtocol,
                       "ensure_initialized",
                       return_value=True):
         with patch.object(wire.StatusBlob,
                           "upload",
                           return_value=False):
             with patch.object(wire.HostPluginProtocol,
                               "_put_page_blob_status",
                               side_effect=wire.HttpError("put failure")) as patch_put:
                 client = wire.WireProtocol(wireserver_url).client
                 client.get_goal_state = Mock(return_value=test_goal_state)
                 client.ext_conf = wire.ExtensionsConfig(None)
                 client.ext_conf.status_upload_blob = sas_url
                 client.ext_conf.status_upload_blob_type = page_blob_type
                 client.status_blob.set_vm_status(status)
                 client.upload_status_blob()
                 self.assertTrue(patch_put.call_count == 1,
                                 "Fallback was not engaged")
                 self.assertFalse(wire.HostPluginProtocol.is_default_channel())
Esempio n. 6
0
 def test_put_status_error_reporting(self):
     """
     Validate the telemetry when uploading status fails
     """
     test_goal_state = wire.GoalState(WireProtocolData(DATA_FILE).goal_state)
     status = restapi.VMStatus(status="Ready",
                               message="Guest Agent is running")
     wire.HostPluginProtocol.set_default_channel(False)
     with patch.object(wire.StatusBlob,
                       "upload",
                       return_value=False):
         wire_protocol_client = wire.WireProtocol(wireserver_url).client
         wire_protocol_client.get_goal_state = Mock(return_value=test_goal_state)
         wire_protocol_client.ext_conf = wire.ExtensionsConfig(None)
         wire_protocol_client.ext_conf.status_upload_blob = sas_url
         wire_protocol_client.status_blob.set_vm_status(status)
         put_error = wire.HttpError("put status http error")
         with patch.object(event,
                           "add_event") as patch_add_event:
             with patch.object(restutil,
                               "http_put",
                               side_effect=put_error) as patch_http_put:
                 with patch.object(wire.HostPluginProtocol,
                                   "ensure_initialized", return_value=True):
                     wire_protocol_client.upload_status_blob()
                     self.assertFalse(wire.HostPluginProtocol.is_default_channel())
                     self.assertTrue(patch_add_event.call_count == 1)
Esempio n. 7
0
 def test_fallback(self):
     """
     Validate fallback to upload status using HostGAPlugin is happening when
     status reporting via default method is unsuccessful
     """
     test_goal_state = wire.GoalState(WireProtocolData(DATA_FILE).goal_state)
     status = restapi.VMStatus(status="Ready", message="Guest Agent is running")
     with patch.object(wire.HostPluginProtocol,
                       "ensure_initialized",
                       return_value=True):
         with patch.object(wire.StatusBlob, "upload", return_value=False) as patch_upload:
             with patch.object(wire.HostPluginProtocol,
                               "_put_page_blob_status") as patch_put:
                 wire_protocol_client = wire.WireProtocol(wireserver_url).client
                 wire_protocol_client.get_goal_state = Mock(return_value=test_goal_state)
                 wire_protocol_client.ext_conf = wire.ExtensionsConfig(None)
                 wire_protocol_client.ext_conf.status_upload_blob = sas_url
                 wire_protocol_client.ext_conf.status_upload_blob_type = page_blob_type
                 wire_protocol_client.status_blob.set_vm_status(status)
                 wire_protocol_client.upload_status_blob()
                 self.assertEqual(patch_upload.call_count, 1)
                 self.assertTrue(patch_put.call_count == 1,
                                 "Fallback was not engaged")
                 self.assertTrue(patch_put.call_args[0][0] == sas_url)
                 self.assertTrue(wire.HostPluginProtocol.is_default_channel())
                 wire.HostPluginProtocol.set_default_channel(False)
Esempio n. 8
0
    def test_put_status_error_reporting(self, patch_add_event):
        """
        Validate the telemetry when uploading status fails
        """
        test_goal_state = wire.GoalState(
            WireProtocolData(DATA_FILE).goal_state)
        status = restapi.VMStatus(status="Ready",
                                  message="Guest Agent is running")
        wire.HostPluginProtocol.set_default_channel(False)
        with patch.object(wire.StatusBlob, "upload", return_value=False):
            wire_protocol_client = wire.WireProtocol(wireserver_url).client
            wire_protocol_client.get_goal_state = Mock(
                return_value=test_goal_state)
            wire_protocol_client.ext_conf = wire.ExtensionsConfig(None)
            wire_protocol_client.ext_conf.status_upload_blob = sas_url
            wire_protocol_client.status_blob.set_vm_status(status)
            put_error = wire.HttpError("put status http error")
            with patch.object(restutil, "http_put",
                              side_effect=put_error) as patch_http_put:
                with patch.object(wire.HostPluginProtocol,
                                  "ensure_initialized",
                                  return_value=True):
                    wire_protocol_client.upload_status_blob()

                    # The agent tries to upload via HostPlugin and that fails due to
                    # http_put having a side effect of "put_error"
                    #
                    # The agent tries to upload using a direct connection, and that succeeds.
                    self.assertEqual(
                        1, wire_protocol_client.status_blob.upload.call_count)
                    # The agent never touches the default protocol is this code path, so no change.
                    self.assertFalse(
                        wire.HostPluginProtocol.is_default_channel())
                    # The agent never logs a telemetry event for a bad HTTP call
                    self.assertEqual(patch_add_event.call_count, 0)
Esempio n. 9
0
 def test_fallback(self):
     """
     Status now defaults to HostPlugin. Validate that any errors on the public
     channel are ignored.  Validate that the default channel is never changed
     as part of status upload.
     """
     test_goal_state = wire.GoalState(
         WireProtocolData(DATA_FILE).goal_state)
     status = restapi.VMStatus(status="Ready",
                               message="Guest Agent is running")
     with patch.object(wire.HostPluginProtocol,
                       "ensure_initialized",
                       return_value=True):
         with patch.object(wire.StatusBlob, "upload",
                           return_value=False) as patch_upload:
             with patch.object(wire.HostPluginProtocol,
                               "_put_page_blob_status") as patch_put:
                 wire_protocol_client = wire.WireProtocol(
                     wireserver_url).client
                 wire_protocol_client.get_goal_state = Mock(
                     return_value=test_goal_state)
                 wire_protocol_client.ext_conf = wire.ExtensionsConfig(None)
                 wire_protocol_client.ext_conf.status_upload_blob = sas_url
                 wire_protocol_client.ext_conf.status_upload_blob_type = page_blob_type
                 wire_protocol_client.status_blob.set_vm_status(status)
                 wire_protocol_client.upload_status_blob()
                 self.assertEqual(patch_upload.call_count, 0)
                 self.assertTrue(patch_put.call_count == 1,
                                 "Fallback was not engaged")
                 self.assertTrue(patch_put.call_args[0][0] == sas_url)
                 self.assertFalse(
                     wire.HostPluginProtocol.is_default_channel())
Esempio n. 10
0
 def _init_host(self):
     test_goal_state = wire.GoalState(
         WireProtocolData(DATA_FILE).goal_state)
     host_plugin = wire.HostPluginProtocol(wireserver_url,
                                           test_goal_state.container_id,
                                           test_goal_state.role_config_name)
     self.assertTrue(host_plugin.health_service is not None)
     return host_plugin
Esempio n. 11
0
    def test_validate_page_blobs(self):
        """Validate correct set of data is sent for page blobs"""
        wire_protocol_client = wire.WireProtocol(wireserver_url).client
        test_goal_state = wire.GoalState(
            WireProtocolData(DATA_FILE).goal_state)

        host_client = wire.HostPluginProtocol(wireserver_url,
                                              test_goal_state.container_id,
                                              test_goal_state.role_config_name)

        self.assertFalse(host_client.is_initialized)
        self.assertTrue(host_client.api_versions is None)

        status_blob = wire_protocol_client.status_blob
        status_blob.data = faux_status
        status_blob.type = page_blob_type
        status_blob.vm_status = restapi.VMStatus(message="Ready",
                                                 status="Ready")

        exp_method = 'PUT'
        exp_url = hostplugin_status_url

        page_status = bytearray(status_blob.data, encoding='utf-8')
        page_size = int((len(page_status) + 511) / 512) * 512
        page_status = bytearray(status_blob.data.ljust(page_size),
                                encoding='utf-8')
        page = bytearray(page_size)
        page[0:page_size] = page_status[0:len(page_status)]
        mock_response = MockResponse('', httpclient.OK)

        with patch.object(restutil, "http_request",
                          return_value=mock_response) as patch_http:
            with patch.object(wire.HostPluginProtocol,
                              "get_api_versions") as patch_get:
                patch_get.return_value = api_versions
                host_client.put_vm_status(status_blob, sas_url)

                self.assertTrue(patch_http.call_count == 3)

                # first call is to host plugin
                exp_data = self._hostplugin_data(
                    status_blob.get_page_blob_create_headers(page_size))
                self._validate_hostplugin_args(patch_http.call_args_list[0],
                                               test_goal_state, exp_method,
                                               exp_url, exp_data)

                # second call is to health service
                self.assertEqual('POST', patch_http.call_args_list[1][0][0])
                self.assertEqual(health_service_url,
                                 patch_http.call_args_list[1][0][1])

                # last call is to host plugin
                exp_data = self._hostplugin_data(
                    status_blob.get_page_blob_page_headers(0, page_size), page)
                exp_data['requestUri'] += "?comp=page"
                self._validate_hostplugin_args(patch_http.call_args_list[2],
                                               test_goal_state, exp_method,
                                               exp_url, exp_data)
Esempio n. 12
0
    def test_validate_http_put(self):
        """Validate correct set of data is sent to HostGAPlugin when reporting VM status"""
        test_goal_state = wire.GoalState(
            WireProtocolData(DATA_FILE).goal_state)
        expected_url = "http://168.63.129.16:32526/status"
        expected_headers = {
            'x-ms-version': '2015-09-01',
            "Content-type": "application/json",
            "x-ms-containerid": test_goal_state.container_id,
            "x-ms-host-config-name": test_goal_state.role_config_name
        }
        expected_content = '{"content": "eyJkdW1teSI6ICJkYXRhIn0=", ' \
                           '"headers": [{"headerName": "x-ms-version", ' \
                           '"headerValue": "2014-02-14"}, ' \
                           '{"headerName": "x-ms-blob-type", "headerValue": ' \
                           '"BlockBlob"}], ' \
                           '"requestUri": "http://sas_url"}'

        host_client = wire.HostPluginProtocol(wireserver_url,
                                              test_goal_state.container_id,
                                              test_goal_state.role_config_name)
        self.assertFalse(host_client.is_initialized)
        self.assertTrue(host_client.api_versions is None)
        status_blob = wire.StatusBlob(None)
        status_blob.vm_status = restapi.VMStatus(message="Ready",
                                                 status="Ready")
        status_blob.data = '{"dummy": "data"}'
        status_blob.type = "BlockBlob"
        with patch.object(wire.HostPluginProtocol,
                          "get_api_versions") as patch_get:
            patch_get.return_value = api_versions
            with patch.object(restapi.restutil, "http_put") as patch_put:
                patch_put.return_value = MagicMock()
                host_client.put_vm_status(status_blob, sas_url)
                self.assertTrue(host_client.is_initialized)
                self.assertFalse(host_client.api_versions is None)
                self.assertTrue(patch_put.call_count == 1)
                self.assertTrue(patch_put.call_args[0][0] == expected_url)
                self.assertTrue(
                    patch_put.call_args[1]['data'] == expected_content)
                self.assertTrue(
                    patch_put.call_args[1]['headers'] == expected_headers)
Esempio n. 13
0
    def test_fallback(self):
        """
        Validate fallback to upload status using HostGAPlugin is happening when status reporting via
        default method is unsuccessful
        """
        test_goal_state = wire.GoalState(
            WireProtocolData(DATA_FILE).goal_state)

        with patch.object(wire.HostPluginProtocol,
                          "put_vm_status") as patch_put:
            with patch.object(wire.StatusBlob, "upload",
                              return_value=False) as patch_upload:
                wire_protocol_client = wire.WireProtocol(wireserver_url).client
                wire_protocol_client.get_goal_state = Mock(
                    return_value=test_goal_state)
                wire_protocol_client.ext_conf = wire.ExtensionsConfig(None)
                wire_protocol_client.ext_conf.status_upload_blob = sas_url
                wire_protocol_client.upload_status_blob()
                self.assertTrue(patch_put.call_count == 1,
                                "Fallback was not engaged")
                self.assertTrue(patch_put.call_args[0][1] == sas_url)
Esempio n. 14
0
    def test_fallback_channel_failure(self, patch_update, patch_put,
                                      patch_upload, _):
        """
        When host plugin returns a 500, and direct fails, we should raise a ProtocolError
        """
        test_goal_state = wire.GoalState(
            WireProtocolData(DATA_FILE).goal_state)
        status = restapi.VMStatus(status="Ready",
                                  message="Guest Agent is running")

        wire_protocol_client = wire.WireProtocol(wireserver_url).client
        wire_protocol_client.get_goal_state = Mock(
            return_value=test_goal_state)
        wire_protocol_client.ext_conf = wire.ExtensionsConfig(None)
        wire_protocol_client.ext_conf.status_upload_blob = sas_url
        wire_protocol_client.ext_conf.status_upload_blob_type = page_blob_type
        wire_protocol_client.status_blob.set_vm_status(status)

        # act
        self.assertRaises(wire.ProtocolError,
                          wire_protocol_client.upload_status_blob)

        # assert direct route is not called
        self.assertEqual(1, patch_upload.call_count,
                         "Direct channel was not used")

        # assert host plugin route is called
        self.assertEqual(1, patch_put.call_count, "Host plugin was not used")

        # assert update goal state is called twice, forced=True on the second
        self.assertEqual(1, patch_update.call_count,
                         "Update goal state unexpected call count")
        self.assertEqual(0, len(patch_update.call_args[1]),
                         "Update goal state unexpected call count")

        # ensure the correct url is used
        self.assertEqual(sas_url, patch_put.call_args[0][0])

        # ensure host plugin is not set as default
        self.assertFalse(wire.HostPluginProtocol.is_default_channel())
Esempio n. 15
0
    def test_fallback_channel_410(self, patch_refresh_host_plugin,
                                  patch_update, patch_put, patch_upload, _):
        """
        When host plugin returns a 410, we should force the goal state update and return
        """
        test_goal_state = wire.GoalState(
            WireProtocolData(DATA_FILE).goal_state)
        status = restapi.VMStatus(status="Ready",
                                  message="Guest Agent is running")

        wire_protocol_client = wire.WireProtocol(wireserver_url).client
        wire_protocol_client.get_goal_state = Mock(
            return_value=test_goal_state)
        wire_protocol_client.ext_conf = wire.ExtensionsConfig(None)
        wire_protocol_client.ext_conf.status_upload_blob = sas_url
        wire_protocol_client.ext_conf.status_upload_blob_type = page_blob_type
        wire_protocol_client.status_blob.set_vm_status(status)

        # act
        wire_protocol_client.upload_status_blob()

        # assert direct route is not called
        self.assertEqual(0, patch_upload.call_count, "Direct channel was used")

        # assert host plugin route is called
        self.assertEqual(1, patch_put.call_count, "Host plugin was not used")

        # assert update goal state is called with no arguments (forced=False), then update_host_plugin_from_goal_state is called
        self.assertEqual(1, patch_update.call_count,
                         "Update goal state unexpected call count")
        self.assertEqual(0, len(patch_update.call_args[1]),
                         "Update goal state unexpected argument count")
        self.assertEqual(1, patch_refresh_host_plugin.call_count,
                         "Refresh host plugin unexpected call count")

        # ensure the correct url is used
        self.assertEqual(sas_url, patch_put.call_args[0][0])

        # ensure host plugin is not set as default
        self.assertFalse(wire.HostPluginProtocol.is_default_channel())
Esempio n. 16
0
    def test_default_channel(self, patch_update, patch_put, patch_upload, _):
        """
        Status now defaults to HostPlugin. Validate that any errors on the public
        channel are ignored.  Validate that the default channel is never changed
        as part of status upload.
        """
        test_goal_state = wire.GoalState(
            WireProtocolData(DATA_FILE).goal_state)
        status = restapi.VMStatus(status="Ready",
                                  message="Guest Agent is running")

        wire_protocol_client = wire.WireProtocol(wireserver_url).client
        wire_protocol_client.get_goal_state = Mock(
            return_value=test_goal_state)
        wire_protocol_client.ext_conf = wire.ExtensionsConfig(None)
        wire_protocol_client.ext_conf.status_upload_blob = sas_url
        wire_protocol_client.ext_conf.status_upload_blob_type = page_blob_type
        wire_protocol_client.status_blob.set_vm_status(status)

        # act
        wire_protocol_client.upload_status_blob()

        # assert direct route is not called
        self.assertEqual(0, patch_upload.call_count, "Direct channel was used")

        # assert host plugin route is called
        self.assertEqual(1, patch_put.call_count, "Host plugin was not used")

        # assert update goal state is only called once, non-forced
        self.assertEqual(1, patch_update.call_count, "Unexpected call count")
        self.assertEqual(0, len(patch_update.call_args[1]),
                         "Unexpected parameters")

        # ensure the correct url is used
        self.assertEqual(sas_url, patch_put.call_args[0][0])

        # ensure host plugin is not set as default
        self.assertFalse(wire.HostPluginProtocol.is_default_channel())