diff --git a/lib/ansible/constants.py b/lib/ansible/constants.py index 250b27a26f..79fe78c640 100644 --- a/lib/ansible/constants.py +++ b/lib/ansible/constants.py @@ -104,7 +104,7 @@ DEFAULT_REMOTE_PASS = None DEFAULT_SUBSET = None DEFAULT_SU_PASS = None # FIXME: expand to other plugins, but never doc fragments -CONFIGURABLE_PLUGINS = ('cache', 'callback', 'connection', 'inventory', 'lookup', 'shell', 'cliconf') +CONFIGURABLE_PLUGINS = ('cache', 'callback', 'connection', 'inventory', 'lookup', 'shell', 'cliconf', 'httpapi') # NOTE: always update the docs/docsite/Makefile to match DOCUMENTABLE_PLUGINS = CONFIGURABLE_PLUGINS + ('module', 'strategy', 'vars') IGNORE_FILES = ("COPYING", "CONTRIBUTING", "LICENSE", "README", "VERSION", "GUIDELINES") # ignore during module search diff --git a/lib/ansible/plugins/httpapi/ftd.py b/lib/ansible/plugins/httpapi/ftd.py index b0a623aeee..2b1f45c5f2 100644 --- a/lib/ansible/plugins/httpapi/ftd.py +++ b/lib/ansible/plugins/httpapi/ftd.py @@ -20,6 +20,33 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type +DOCUMENTATION = """ +--- +author: Ansible Networking Team +httpapi : ftd +short_description: HttpApi Plugin for Cisco ASA Firepower device +description: + - This HttpApi plugin provides methods to connect to Cisco ASA firepower + devices over a HTTP(S)-based api. +version_added: "2.7" +options: + token_path: + type: str + description: + - Specifies the api token path of the FTD device + default: '/api/fdm/v2/fdm/token' + vars: + - name: ansible_httpapi_ftd_token_path + + spec_path: + type: str + description: + - Specifies the api spec path of the FTD device + default: '/apispec/ngfw.json' + vars: + - name: ansible_httpapi_ftd_spec_path +""" + import json import os import re @@ -39,9 +66,6 @@ BASE_HEADERS = { 'Content-Type': 'application/json', 'Accept': 'application/json' } -API_TOKEN_PATH_ENV_VAR = 'FTD_API_TOKEN_PATH' -DEFAULT_API_TOKEN_PATH = '/api/fdm/v2/fdm/token' -API_SPEC_PATH = '/apispec/ngfw.json' TOKEN_EXPIRATION_STATUS_CODE = 408 UNAUTHORIZED_STATUS_CODE = 401 @@ -49,6 +73,7 @@ UNAUTHORIZED_STATUS_CODE = 401 class HttpApi(HttpApiBase): def __init__(self, connection): + super(HttpApi, self).__init__(connection) self.connection = connection self.access_token = None self.refresh_token = None @@ -168,9 +193,11 @@ class HttpApi(HttpApiBase): headers['Authorization'] = 'Bearer %s' % self.access_token return headers - @staticmethod - def _get_api_token_path(): - return os.environ.get(API_TOKEN_PATH_ENV_VAR, DEFAULT_API_TOKEN_PATH) + def _get_api_spec_path(self): + return self.get_option('spec_path') + + def _get_api_token_path(self): + return self.get_option('token_path') @staticmethod def _response_to_json(response_data): @@ -199,7 +226,8 @@ class HttpApi(HttpApiBase): @property def api_spec(self): if self._api_spec is None: - response = self.send_request(url_path=API_SPEC_PATH, http_method=HTTPMethod.GET) + spec_path_url = self._get_api_spec_path() + response = self.send_request(url_path=spec_path_url, http_method=HTTPMethod.GET) if response[ResponseParams.SUCCESS]: self._api_spec = FdmSwaggerParser().parse_spec(response[ResponseParams.RESPONSE]) else: diff --git a/test/units/plugins/httpapi/test_ftd.py b/test/units/plugins/httpapi/test_ftd.py index d3585871e7..4832b47b8f 100644 --- a/test/units/plugins/httpapi/test_ftd.py +++ b/test/units/plugins/httpapi/test_ftd.py @@ -29,7 +29,7 @@ from ansible.module_utils.connection import ConnectionError from ansible.module_utils.network.ftd.common import HTTPMethod, ResponseParams from ansible.module_utils.network.ftd.fdm_swagger_client import SpecProp, FdmSwaggerParser from ansible.module_utils.six import BytesIO, PY3, StringIO -from ansible.plugins.httpapi.ftd import HttpApi, API_TOKEN_PATH_ENV_VAR +from ansible.plugins.httpapi.ftd import HttpApi if PY3: BUILTINS_NAME = 'builtins' @@ -37,12 +37,25 @@ else: BUILTINS_NAME = '__builtin__' +class FakeFtdHttpApiPlugin(HttpApi): + def __init__(self, conn): + super(FakeFtdHttpApiPlugin, self).__init__(conn) + self.hostvars = { + 'token_path': '/testLoginUrl', + 'spec_path': '/testSpecUrl' + } + + def get_option(self, var): + return self.hostvars[var] + + class TestFtdHttpApi(unittest.TestCase): def setUp(self): self.connection_mock = mock.Mock() - self.ftd_plugin = HttpApi(self.connection_mock) + self.ftd_plugin = FakeFtdHttpApiPlugin(self.connection_mock) self.ftd_plugin.access_token = 'ACCESS_TOKEN' + self.ftd_plugin._load_name = 'httpapi' def test_login_should_request_tokens_when_no_refresh_token(self): self.connection_mock.send.return_value = self._connection_response( @@ -69,15 +82,17 @@ class TestFtdHttpApi(unittest.TestCase): expected_body = json.dumps({'grant_type': 'refresh_token', 'refresh_token': 'REFRESH_TOKEN'}) self.connection_mock.send.assert_called_once_with(mock.ANY, expected_body, headers=mock.ANY, method=mock.ANY) - @patch.dict(os.environ, {API_TOKEN_PATH_ENV_VAR: '/testLoginUrl'}) - def test_login_should_use_env_variable_when_set(self): + def test_login_should_use_host_variable_when_set(self): + temp_token_path = self.ftd_plugin.hostvars['token_path'] + self.ftd_plugin.hostvars['token_path'] = '/testFakeLoginUrl' self.connection_mock.send.return_value = self._connection_response( {'access_token': 'ACCESS_TOKEN', 'refresh_token': 'REFRESH_TOKEN'} ) self.ftd_plugin.login('foo', 'bar') - self.connection_mock.send.assert_called_once_with('/testLoginUrl', mock.ANY, headers=mock.ANY, method=mock.ANY) + self.connection_mock.send.assert_called_once_with('/testFakeLoginUrl', mock.ANY, headers=mock.ANY, method=mock.ANY) + self.ftd_plugin.hostvars['token_path'] = temp_token_path def test_login_raises_exception_when_no_refresh_token_and_no_credentials(self): with self.assertRaises(AnsibleConnectionFailure) as res: