Add POST support for _http_request when body is empty

On call home, packet metadata service requires to
perform a POST with an empty body.

Adding support for POST on an empty body and support for
all HTTP methods.

Partially implements: blueprint packet-metadata-suport

Change-Id: Ib1902c54ea3c4552313adddb3f944ea80a2a7fa0
This commit is contained in:
Adrian Vladu 2017-06-20 14:04:30 +03:00
parent 526d939240
commit 65680437e9
4 changed files with 43 additions and 30 deletions

View File

@ -248,18 +248,21 @@ class BaseHTTPMetadataService(BaseMetadataService):
else:
return self._https_allow_insecure
def _http_request(self, url, data=None, headers=None):
def _http_request(self, url, data=None, headers=None, method=None):
"""Get content for received url."""
if not url.startswith("http"):
url = requests.compat.urljoin(self._base_url, url)
request_action = requests.get if not data else requests.post
if not data:
LOG.debug('Getting metadata from: %s', url)
else:
LOG.debug('Posting data to %s', url)
if not method:
if data:
method = "POST"
else:
method = "GET"
method = method.upper()
response = request_action(url=url, data=data, headers=headers,
verify=self._verify_https_request())
LOG.debug('Executing http request %s at %s', method, url)
response = requests.request(method=method, url=url, data=data,
headers=headers,
verify=self._verify_https_request())
response.raise_for_status()
return response.content

View File

@ -97,14 +97,15 @@ class MaaSHttpService(base.BaseHTTPMetadataService):
headers = client.sign(url, realm=realm)[1]
return headers
def _http_request(self, url, data=None, headers=None):
def _http_request(self, url, data=None, headers=None, method=None):
"""Get content for received url."""
if not url.startswith("http"):
url = requests.compat.urljoin(self._base_url, url)
headers = {} if headers is None else headers
headers.update(self._get_oauth_headers(url))
return super(MaaSHttpService, self)._http_request(url, data, headers)
return super(MaaSHttpService, self)._http_request(url, data, headers,
method)
def get_host_name(self):
return self._get_cache_data('%s/meta-data/local-hostname' %

View File

@ -80,12 +80,12 @@ class TestBaseHTTPMetadataService(unittest.TestCase):
def test_verify_https_request_with_ca_bundle(self):
self._test_verify_https_request(https_ca_bundle="/path/to/resource")
@mock.patch('requests.post')
@mock.patch('requests.get')
@mock.patch('requests.request')
@mock.patch("cloudbaseinit.metadata.services.base.BaseHTTPMetadataService."
"_verify_https_request")
def _test_http_request(self, mock_verify, mock_get, mock_post,
mock_url, mock_data=None, mock_headers=None):
def _test_http_request(self, mock_verify, mock_request, mock_url,
mock_data=None, mock_headers=None, mock_method=None,
expected_method='GET'):
if not mock_url.startswith('http'):
mock_url = requests.compat.urljoin(self._mock_base_url, mock_url)
@ -93,24 +93,17 @@ class TestBaseHTTPMetadataService(unittest.TestCase):
mock_response_status = mock.Mock()
mock_response.raise_for_status = mock_response_status
mock_response.content = mock.sentinel.content
mock_request.return_value = mock_response
mock_get.return_value = mock_response
mock_post.return_value = mock_response
mock_verify.return_value = mock.sentinel.verify
response = self._service._http_request(url=mock_url, data=mock_data,
headers=mock_headers)
headers=mock_headers,
method=mock_method)
if mock_data:
mock_post.assert_called_once_with(
url=mock_url, data=mock_data, headers=mock_headers,
verify=mock.sentinel.verify
)
else:
mock_get.assert_called_once_with(
url=mock_url, data=mock_data, headers=mock_headers,
verify=mock.sentinel.verify
)
mock_request.assert_called_once_with(
method=expected_method, url=mock_url, data=mock_data,
headers=mock_headers, verify=mock.sentinel.verify)
mock_response_status.assert_called_once_with()
self.assertEqual(response, mock.sentinel.content)
@ -118,12 +111,28 @@ class TestBaseHTTPMetadataService(unittest.TestCase):
def test_http_get_request(self):
self._test_http_request(mock_url="/path/to/resource",
mock_data=None,
mock_headers={})
mock_headers={}, expected_method="GET")
def test_http_post_request(self):
self._test_http_request(mock_url="/path/to/resource",
mock_data={"X-Cloudbase-Init", True},
mock_headers={})
mock_headers={}, expected_method="POST")
def test_http_force_post_request(self):
self._test_http_request(mock_url="/path/to/resource",
mock_data=None, mock_headers={},
mock_method="post", expected_method="POST")
def test_http_force_get_request(self):
self._test_http_request(mock_url="/path/to/resource",
mock_data={"X-Cloudbase-Init", True},
mock_headers={}, mock_method="get",
expected_method="GET")
def test_http_force_head_request(self):
self._test_http_request(mock_url="/path/to/resource",
mock_headers={}, mock_method="head",
expected_method="HEAD")
@mock.patch('requests.compat.urljoin')
@mock.patch("cloudbaseinit.metadata.services.base."

View File

@ -100,7 +100,7 @@ class MaaSHttpServiceTest(unittest.TestCase):
def test_http_request(self, mock_ouath_headers, mock_http_request):
mock_url = "fake.url"
self._maasservice._http_request(mock_url)
mock_http_request.assert_called_once_with(mock_url, None, {})
mock_http_request.assert_called_once_with(mock_url, None, {}, None)
@mock.patch("cloudbaseinit.metadata.services.maasservice.MaaSHttpService"
"._get_cache_data")