mirror of
https://github.com/ansible-collections/google.cloud.git
synced 2025-04-09 04:10:27 -07:00
GcpSession refactor (changing how HTTP requests are sent) (#353)
Signed-off-by: Modular Magician <magic-modules@google.com>
This commit is contained in:
parent
2678243563
commit
f494ff4841
2 changed files with 261 additions and 31 deletions
|
@ -78,53 +78,94 @@ class GcpSession(object):
|
||||||
self._validate()
|
self._validate()
|
||||||
|
|
||||||
def get(self, url, body=None, **kwargs):
|
def get(self, url, body=None, **kwargs):
|
||||||
kwargs.update({'json': body, 'headers': self._headers()})
|
"""
|
||||||
try:
|
This method should be avoided in favor of full_get
|
||||||
return self.session().get(url, **kwargs)
|
"""
|
||||||
except getattr(requests.exceptions, 'RequestException') as inst:
|
kwargs.update({'json': body})
|
||||||
self.module.fail_json(msg=inst.message)
|
return self.full_get(url, **kwargs)
|
||||||
|
|
||||||
def post(self, url, body=None, headers=None, **kwargs):
|
def post(self, url, body=None, headers=None, **kwargs):
|
||||||
if headers:
|
"""
|
||||||
headers = self._merge_dictionaries(headers, self._headers())
|
This method should be avoided in favor of full_post
|
||||||
else:
|
"""
|
||||||
headers = self._headers()
|
kwargs.update({'json': body, 'headers': headers})
|
||||||
|
return self.full_post(url, **kwargs)
|
||||||
try:
|
|
||||||
return self.session().post(url, json=body, headers=headers)
|
|
||||||
except getattr(requests.exceptions, 'RequestException') as inst:
|
|
||||||
self.module.fail_json(msg=inst.message)
|
|
||||||
|
|
||||||
def post_contents(self, url, file_contents=None, headers=None, **kwargs):
|
def post_contents(self, url, file_contents=None, headers=None, **kwargs):
|
||||||
if headers:
|
"""
|
||||||
headers = self._merge_dictionaries(headers, self._headers())
|
This method should be avoided in favor of full_post
|
||||||
else:
|
"""
|
||||||
headers = self._headers()
|
kwargs.update({'data': file_contents, 'headers': headers})
|
||||||
|
return self.full_post(url, **kwargs)
|
||||||
try:
|
|
||||||
return self.session().post(url, data=file_contents, headers=headers)
|
|
||||||
except getattr(requests.exceptions, 'RequestException') as inst:
|
|
||||||
self.module.fail_json(msg=inst.message)
|
|
||||||
|
|
||||||
def delete(self, url, body=None):
|
def delete(self, url, body=None):
|
||||||
try:
|
"""
|
||||||
return self.session().delete(url, json=body, headers=self._headers())
|
This method should be avoided in favor of full_delete
|
||||||
except getattr(requests.exceptions, 'RequestException') as inst:
|
"""
|
||||||
self.module.fail_json(msg=inst.message)
|
kwargs = {'json': body}
|
||||||
|
return self.full_delete(url, **kwargs)
|
||||||
|
|
||||||
def put(self, url, body=None):
|
def put(self, url, body=None):
|
||||||
|
"""
|
||||||
|
This method should be avoided in favor of full_put
|
||||||
|
"""
|
||||||
|
kwargs = {'json': body}
|
||||||
|
return self.full_put(url, **kwargs)
|
||||||
|
|
||||||
|
def patch(self, url, body=None, **kwargs):
|
||||||
|
"""
|
||||||
|
This method should be avoided in favor of full_patch
|
||||||
|
"""
|
||||||
|
kwargs.update({'json': body})
|
||||||
|
return self.full_patch(url, **kwargs)
|
||||||
|
|
||||||
|
# The following methods fully mimic the requests API and should be used.
|
||||||
|
def full_get(self, url, params=None, **kwargs):
|
||||||
|
kwargs['headers'] = self._set_headers(kwargs.get('headers'))
|
||||||
try:
|
try:
|
||||||
return self.session().put(url, json=body, headers=self._headers())
|
return self.session().get(url, params=params, **kwargs)
|
||||||
|
except getattr(requests.exceptions, 'RequestException') as inst:
|
||||||
|
# Only log the message to avoid logging any sensitive info.
|
||||||
|
self.module.fail_json(msg=inst.message)
|
||||||
|
|
||||||
|
def full_post(self, url, data=None, json=None, **kwargs):
|
||||||
|
kwargs['headers'] = self._set_headers(kwargs.get('headers'))
|
||||||
|
|
||||||
|
try:
|
||||||
|
return self.session().post(url, data=data, json=json, **kwargs)
|
||||||
except getattr(requests.exceptions, 'RequestException') as inst:
|
except getattr(requests.exceptions, 'RequestException') as inst:
|
||||||
self.module.fail_json(msg=inst.message)
|
self.module.fail_json(msg=inst.message)
|
||||||
|
|
||||||
def patch(self, url, body=None, **kwargs):
|
def full_put(self, url, data=None, **kwargs):
|
||||||
kwargs.update({'json': body, 'headers': self._headers()})
|
kwargs['headers'] = self._set_headers(kwargs.get('headers'))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return self.session().patch(url, **kwargs)
|
return self.session().put(url, data=data, **kwargs)
|
||||||
except getattr(requests.exceptions, 'RequestException') as inst:
|
except getattr(requests.exceptions, 'RequestException') as inst:
|
||||||
self.module.fail_json(msg=inst.message)
|
self.module.fail_json(msg=inst.message)
|
||||||
|
|
||||||
|
def full_patch(self, url, data=None, **kwargs):
|
||||||
|
kwargs['headers'] = self._set_headers(kwargs.get('headers'))
|
||||||
|
|
||||||
|
try:
|
||||||
|
return self.session().patch(url, data=data, **kwargs)
|
||||||
|
except getattr(requests.exceptions, 'RequestException') as inst:
|
||||||
|
self.module.fail_json(msg=inst.message)
|
||||||
|
|
||||||
|
def full_delete(self, url, **kwargs):
|
||||||
|
kwargs['headers'] = self._set_headers(kwargs.get('headers'))
|
||||||
|
|
||||||
|
try:
|
||||||
|
return self.session().delete(url, **kwargs)
|
||||||
|
except getattr(requests.exceptions, 'RequestException') as inst:
|
||||||
|
self.module.fail_json(msg=inst.message)
|
||||||
|
|
||||||
|
def _set_headers(self, headers):
|
||||||
|
if headers:
|
||||||
|
return self._merge_dictionaries(headers, self._headers())
|
||||||
|
else:
|
||||||
|
return self._headers()
|
||||||
|
|
||||||
def session(self):
|
def session(self):
|
||||||
return AuthorizedSession(
|
return AuthorizedSession(
|
||||||
self._credentials())
|
self._credentials())
|
||||||
|
|
189
test/units/module_utils/gcp/test_gcp_session.py
Normal file
189
test/units/module_utils/gcp/test_gcp_session.py
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# (c) 2019, Google Inc.
|
||||||
|
#
|
||||||
|
# This file is part of Ansible
|
||||||
|
#
|
||||||
|
# Ansible is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Ansible is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from pytest import importorskip
|
||||||
|
from units.compat import unittest
|
||||||
|
from units.compat.mock import patch
|
||||||
|
from contextlib import contextmanager
|
||||||
|
from ansible.module_utils.gcp_utils import GcpSession
|
||||||
|
import responses
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
importorskip("requests")
|
||||||
|
importorskip("google.auth")
|
||||||
|
importorskip("responses")
|
||||||
|
|
||||||
|
from google.auth.credentials import AnonymousCredentials
|
||||||
|
|
||||||
|
|
||||||
|
class FakeModule(object):
|
||||||
|
def __init__(self, params):
|
||||||
|
self.params = params
|
||||||
|
|
||||||
|
def fail_json(self, **kwargs):
|
||||||
|
raise kwargs["msg"]
|
||||||
|
|
||||||
|
|
||||||
|
class GcpSessionTestCase(unittest.TestCase):
|
||||||
|
success_json = {"status": "SUCCESS"}
|
||||||
|
user_agent = "Google-Ansible-MM-mock"
|
||||||
|
url = "http://www.googleapis.com/compute/test_instance"
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def setup_auth(self):
|
||||||
|
"""
|
||||||
|
This is a context manager that mocks out
|
||||||
|
the google-auth library and uses the built-in
|
||||||
|
AnonymousCredentials for sending requests.
|
||||||
|
"""
|
||||||
|
with patch(
|
||||||
|
"google.oauth2.service_account.Credentials.from_service_account_file"
|
||||||
|
) as mock:
|
||||||
|
with patch.object(
|
||||||
|
AnonymousCredentials, "with_scopes", create=True
|
||||||
|
) as mock2:
|
||||||
|
creds = AnonymousCredentials()
|
||||||
|
mock2.return_value = creds
|
||||||
|
mock.return_value = creds
|
||||||
|
yield
|
||||||
|
|
||||||
|
@responses.activate
|
||||||
|
def test_get(self):
|
||||||
|
responses.add(responses.GET, self.url, status=200, json=self.success_json)
|
||||||
|
|
||||||
|
with self.setup_auth():
|
||||||
|
module = FakeModule(
|
||||||
|
{
|
||||||
|
"scopes": "foo",
|
||||||
|
"service_account_file": "file_name",
|
||||||
|
"project": "test_project",
|
||||||
|
"auth_kind": "serviceaccount",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
session = GcpSession(module, "mock")
|
||||||
|
resp = session.get(self.url)
|
||||||
|
|
||||||
|
assert responses.calls[0].request.headers["User-Agent"] == self.user_agent
|
||||||
|
assert resp.json() == self.success_json
|
||||||
|
assert resp.status_code == 200
|
||||||
|
|
||||||
|
@responses.activate
|
||||||
|
def test_post(self):
|
||||||
|
responses.add(responses.POST, self.url, status=200, json=self.success_json)
|
||||||
|
|
||||||
|
with self.setup_auth():
|
||||||
|
body = {"content": "some_content"}
|
||||||
|
module = FakeModule(
|
||||||
|
{
|
||||||
|
"scopes": "foo",
|
||||||
|
"service_account_file": "file_name",
|
||||||
|
"project": "test_project",
|
||||||
|
"auth_kind": "serviceaccount",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
session = GcpSession(module, "mock")
|
||||||
|
resp = session.post(
|
||||||
|
self.url, body=body, headers={"x-added-header": "my-header"}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Ensure Google header added.
|
||||||
|
assert responses.calls[0].request.headers["User-Agent"] == self.user_agent
|
||||||
|
|
||||||
|
# Ensure all content was passed along.
|
||||||
|
assert responses.calls[0].request.headers["x-added-header"] == "my-header"
|
||||||
|
|
||||||
|
# Ensure proper request was made.
|
||||||
|
assert resp.json() == self.success_json
|
||||||
|
assert resp.status_code == 200
|
||||||
|
|
||||||
|
@responses.activate
|
||||||
|
def test_delete(self):
|
||||||
|
responses.add(responses.DELETE, self.url, status=200, json=self.success_json)
|
||||||
|
|
||||||
|
with self.setup_auth():
|
||||||
|
body = {"content": "some_content"}
|
||||||
|
module = FakeModule(
|
||||||
|
{
|
||||||
|
"scopes": "foo",
|
||||||
|
"service_account_file": "file_name",
|
||||||
|
"project": "test_project",
|
||||||
|
"auth_kind": "serviceaccount",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
session = GcpSession(module, "mock")
|
||||||
|
resp = session.delete(self.url)
|
||||||
|
|
||||||
|
# Ensure Google header added.
|
||||||
|
assert responses.calls[0].request.headers["User-Agent"] == self.user_agent
|
||||||
|
|
||||||
|
# Ensure proper request was made.
|
||||||
|
assert resp.json() == self.success_json
|
||||||
|
assert resp.status_code == 200
|
||||||
|
|
||||||
|
@responses.activate
|
||||||
|
def test_put(self):
|
||||||
|
responses.add(responses.PUT, self.url, status=200, json=self.success_json)
|
||||||
|
|
||||||
|
with self.setup_auth():
|
||||||
|
body = {"content": "some_content"}
|
||||||
|
module = FakeModule(
|
||||||
|
{
|
||||||
|
"scopes": "foo",
|
||||||
|
"service_account_file": "file_name",
|
||||||
|
"project": "test_project",
|
||||||
|
"auth_kind": "serviceaccount",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
session = GcpSession(module, "mock")
|
||||||
|
resp = session.put(self.url, body={"foo": "bar"})
|
||||||
|
|
||||||
|
# Ensure Google header added.
|
||||||
|
assert responses.calls[0].request.headers["User-Agent"] == self.user_agent
|
||||||
|
|
||||||
|
# Ensure proper request was made.
|
||||||
|
assert resp.json() == self.success_json
|
||||||
|
assert resp.status_code == 200
|
||||||
|
|
||||||
|
@responses.activate
|
||||||
|
def test_patch(self):
|
||||||
|
responses.add(responses.PATCH, self.url, status=200, json=self.success_json)
|
||||||
|
|
||||||
|
with self.setup_auth():
|
||||||
|
body = {"content": "some_content"}
|
||||||
|
module = FakeModule(
|
||||||
|
{
|
||||||
|
"scopes": "foo",
|
||||||
|
"service_account_file": "file_name",
|
||||||
|
"project": "test_project",
|
||||||
|
"auth_kind": "serviceaccount",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
session = GcpSession(module, "mock")
|
||||||
|
resp = session.patch(self.url, body={"foo": "bar"})
|
||||||
|
|
||||||
|
# Ensure Google header added.
|
||||||
|
assert responses.calls[0].request.headers["User-Agent"] == self.user_agent
|
||||||
|
|
||||||
|
# Ensure proper request was made.
|
||||||
|
assert resp.json() == self.success_json
|
||||||
|
assert resp.status_code == 200
|
Loading…
Add table
Reference in a new issue