def setUp(self, fetch_system_info_mock): self._conn = mock.MagicMock() self._resource = BaseConfigurationResource(self._conn) fetch_system_info_mock.return_value = { 'databaseInfo': { 'buildVersion': '6.3.0' } }
def _resource_execute_operation(params, connection): with mock.patch.object(BaseConfigurationResource, '_fetch_system_info') as fetch_system_info_mock: fetch_system_info_mock.return_value = { 'databaseInfo': { 'buildVersion': '6.3.0' } } resource = BaseConfigurationResource(connection) op_name = params['operation'] resp = resource.execute_operation(op_name, params) return resp
def main(): fields = dict(device_hostname=dict(type='str', required=True), device_username=dict(type='str', required=False, default='admin'), device_password=dict(type='str', required=True, no_log=True), device_sudo_password=dict(type='str', required=False, no_log=True), device_new_password=dict(type='str', required=False, no_log=True), device_ip=dict(type='str', required=False), device_netmask=dict(type='str', required=False), device_gateway=dict(type='str', required=False), device_model=dict(type='str', required=False, choices=FtdModel.supported_models()), dns_server=dict(type='str', required=False), search_domains=dict(type='str', required=False, default='cisco.com'), console_ip=dict(type='str', required=True), console_port=dict(type='str', required=True), console_username=dict(type='str', required=True), console_password=dict(type='str', required=True, no_log=True), rommon_file_location=dict(type='str', required=True), image_file_location=dict(type='str', required=True), image_version=dict(type='str', required=True), force_install=dict(type='bool', required=False, default=False)) module = AnsibleModule(argument_spec=fields) assert_kick_is_installed(module) use_local_connection = module._socket_path is None if use_local_connection: check_required_params_for_local_connection(module, module.params) platform_model = module.params['device_model'] check_that_model_is_supported(module, platform_model) else: connection = Connection(module._socket_path) resource = BaseConfigurationResource(connection, module.check_mode) system_info = get_system_info(resource) platform_model = module.params['device_model'] or system_info[ 'platformModel'] check_that_model_is_supported(module, platform_model) check_that_update_is_needed(module, system_info) check_management_and_dns_params(resource, module.params) ftd_platform = FtdPlatformFactory.create(platform_model, module.params) ftd_platform.install_ftd_image(module.params) module.exit_json( changed=True, msg='Successfully installed FTD image %s on the firewall device.' % module.params["image_version"])
def test_stringify_name_filter(self, test_api_version, expected_result, connection_mock): filters = {"name": "object_name"} with patch.object(BaseConfigurationResource, '_fetch_system_info') as fetch_system_info_mock: fetch_system_info_mock.return_value = { 'databaseInfo': { 'buildVersion': test_api_version } } resource = BaseConfigurationResource(connection_mock, False) assert resource._stringify_name_filter( filters ) == expected_result, "Unexpected result for version %s" % ( test_api_version)
def test_module_should_fail_if_validation_error_in_path_params( self, connection_mock): connection_mock.get_operation_spec.return_value = { 'method': HTTPMethod.GET, 'url': '/test', 'returnMultipleItems': False } report = { 'path_params': { 'required': ['objects[0].type'], 'invalid_type': [{ 'path': 'objects[3].id', 'expected_type': 'string', 'actually_value': 1 }] } } connection_mock.validate_path_params.return_value = ( False, json.dumps(report, sort_keys=True, indent=4)) with pytest.raises(ValidationError) as e_info: resource = BaseConfigurationResource(connection_mock, False) resource.crud_operation('putTest', {'data': {}}) result = e_info.value.args[0] key = 'Invalid path_params provided' assert result[key] result[key] = json.loads(result[key]) assert result == { key: { 'path_params': { 'invalid_type': [{ 'actually_value': 1, 'expected_type': 'string', 'path': 'objects[3].id' }], 'required': ['objects[0].type'] } } }
def main(): fields = dict(operation=dict(type='str', required=True), data=dict(type='dict'), query_params=dict(type='dict'), path_params=dict(type='dict'), register_as=dict(type='str'), filters=dict(type='dict')) module = AnsibleModule(argument_spec=fields, supports_check_mode=True) params = module.params connection = Connection(module._socket_path) resource = BaseConfigurationResource(connection, module.check_mode) op_name = params['operation'] try: resp = resource.execute_operation(op_name, params) module.exit_json(changed=resource.config_changed, response=resp, ansible_facts=construct_ansible_facts( resp, module.params)) except FtdInvalidOperationNameError as e: module.fail_json(msg='Invalid operation name provided: %s' % e.operation_name) except FtdConfigurationError as e: module.fail_json( msg= 'Failed to execute %s operation because of the configuration error: %s' % (op_name, e.msg)) except FtdServerError as e: module.fail_json( msg= 'Server returned an error trying to execute %s operation. Status code: %s. ' 'Server response: %s' % (op_name, e.code, e.response)) except FtdUnexpectedResponse as e: module.fail_json(msg=e.args[0]) except ValidationError as e: module.fail_json(msg=e.args[0]) except CheckModeException: module.exit_json(changed=False)
class TestUpsertOperationUnitTests(unittest.TestCase): @mock.patch.object(BaseConfigurationResource, '_fetch_system_info') def setUp(self, fetch_system_info_mock): self._conn = mock.MagicMock() self._resource = BaseConfigurationResource(self._conn) fetch_system_info_mock.return_value = { 'databaseInfo': { 'buildVersion': '6.3.0' } } def test_get_operation_name(self): operation_a = mock.MagicMock() operation_b = mock.MagicMock() def checker_wrapper(expected_object): def checker(obj, *args, **kwargs): return obj == expected_object return checker operations = {operation_a: "spec", operation_b: "spec"} assert operation_a == self._resource._get_operation_name( checker_wrapper(operation_a), operations) assert operation_b == self._resource._get_operation_name( checker_wrapper(operation_b), operations) assert self._resource._get_operation_name(checker_wrapper(None), operations) is None @mock.patch.object(BaseConfigurationResource, "_get_operation_name") @mock.patch.object(BaseConfigurationResource, "add_object") def test_add_upserted_object(self, add_object_mock, get_operation_mock): model_operations = mock.MagicMock() params = mock.MagicMock() add_op_name = get_operation_mock.return_value assert add_object_mock.return_value == self._resource._add_upserted_object( model_operations, params) get_operation_mock.assert_called_once_with( self._resource._operation_checker.is_add_operation, model_operations) add_object_mock.assert_called_once_with(add_op_name, params) @mock.patch.object(BaseConfigurationResource, "_get_operation_name") @mock.patch.object(BaseConfigurationResource, "add_object") def test_add_upserted_object_with_no_add_operation(self, add_object_mock, get_operation_mock): model_operations = mock.MagicMock() get_operation_mock.return_value = None with pytest.raises(FtdConfigurationError) as exc_info: self._resource._add_upserted_object(model_operations, mock.MagicMock()) assert ADD_OPERATION_NOT_SUPPORTED_ERROR in str(exc_info.value) get_operation_mock.assert_called_once_with( self._resource._operation_checker.is_add_operation, model_operations) add_object_mock.assert_not_called() @mock.patch.object(BaseConfigurationResource, "_get_operation_name") @mock.patch.object(BaseConfigurationResource, "edit_object") @mock.patch( 'ansible_collections.community.network.plugins.module_utils.network.ftd.configuration.copy_identity_properties' ) @mock.patch( 'ansible_collections.community.network.plugins.module_utils.network.ftd.configuration._set_default' ) def test_edit_upserted_object(self, _set_default_mock, copy_properties_mock, edit_object_mock, get_operation_mock): model_operations = mock.MagicMock() existing_object = mock.MagicMock() params = {'path_params': {}, 'data': {}} result = self._resource._edit_upserted_object(model_operations, existing_object, params) assert result == edit_object_mock.return_value _set_default_mock.assert_has_calls([ mock.call(params, 'path_params', {}), mock.call(params, 'data', {}) ]) get_operation_mock.assert_called_once_with( self._resource._operation_checker.is_edit_operation, model_operations) copy_properties_mock.assert_called_once_with(existing_object, params['data']) edit_object_mock.assert_called_once_with( get_operation_mock.return_value, params) @mock.patch( 'ansible_collections.community.network.plugins.module_utils.network.ftd.configuration.OperationChecker.is_upsert_operation_supported' ) @mock.patch.object(BaseConfigurationResource, "get_operation_specs_by_model_name") @mock.patch.object(BaseConfigurationResource, "_find_object_matching_params") @mock.patch.object(BaseConfigurationResource, "_add_upserted_object") @mock.patch.object(BaseConfigurationResource, "_edit_upserted_object") def test_upsert_object_successfully_added(self, edit_mock, add_mock, find_object, get_operation_mock, is_upsert_supported_mock): params = mock.MagicMock() is_upsert_supported_mock.return_value = True find_object.return_value = None result = self._resource.upsert_object('upsertFoo', params) assert result == add_mock.return_value self._conn.get_model_spec.assert_called_once_with('Foo') is_upsert_supported_mock.assert_called_once_with( get_operation_mock.return_value) get_operation_mock.assert_called_once_with('Foo') find_object.assert_called_once_with('Foo', params) add_mock.assert_called_once_with(get_operation_mock.return_value, params) edit_mock.assert_not_called() @mock.patch( 'ansible_collections.community.network.plugins.module_utils.network.ftd.configuration.equal_objects' ) @mock.patch( 'ansible_collections.community.network.plugins.module_utils.network.ftd.configuration.OperationChecker.is_upsert_operation_supported' ) @mock.patch.object(BaseConfigurationResource, "get_operation_specs_by_model_name") @mock.patch.object(BaseConfigurationResource, "_find_object_matching_params") @mock.patch.object(BaseConfigurationResource, "_add_upserted_object") @mock.patch.object(BaseConfigurationResource, "_edit_upserted_object") def test_upsert_object_successfully_edited(self, edit_mock, add_mock, find_object, get_operation_mock, is_upsert_supported_mock, equal_objects_mock): params = mock.MagicMock() existing_obj = mock.MagicMock() is_upsert_supported_mock.return_value = True find_object.return_value = existing_obj equal_objects_mock.return_value = False result = self._resource.upsert_object('upsertFoo', params) assert result == edit_mock.return_value self._conn.get_model_spec.assert_called_once_with('Foo') get_operation_mock.assert_called_once_with('Foo') is_upsert_supported_mock.assert_called_once_with( get_operation_mock.return_value) add_mock.assert_not_called() equal_objects_mock.assert_called_once_with(existing_obj, params[ParamName.DATA]) edit_mock.assert_called_once_with(get_operation_mock.return_value, existing_obj, params) @mock.patch( 'ansible_collections.community.network.plugins.module_utils.network.ftd.configuration.equal_objects' ) @mock.patch( 'ansible_collections.community.network.plugins.module_utils.network.ftd.configuration.OperationChecker.is_upsert_operation_supported' ) @mock.patch.object(BaseConfigurationResource, "get_operation_specs_by_model_name") @mock.patch.object(BaseConfigurationResource, "_find_object_matching_params") @mock.patch.object(BaseConfigurationResource, "_add_upserted_object") @mock.patch.object(BaseConfigurationResource, "_edit_upserted_object") def test_upsert_object_returned_without_modifications( self, edit_mock, add_mock, find_object, get_operation_mock, is_upsert_supported_mock, equal_objects_mock): params = mock.MagicMock() existing_obj = mock.MagicMock() is_upsert_supported_mock.return_value = True find_object.return_value = existing_obj equal_objects_mock.return_value = True result = self._resource.upsert_object('upsertFoo', params) assert result == existing_obj self._conn.get_model_spec.assert_called_once_with('Foo') get_operation_mock.assert_called_once_with('Foo') is_upsert_supported_mock.assert_called_once_with( get_operation_mock.return_value) add_mock.assert_not_called() equal_objects_mock.assert_called_once_with(existing_obj, params[ParamName.DATA]) edit_mock.assert_not_called() @mock.patch( 'ansible_collections.community.network.plugins.module_utils.network.ftd.configuration.OperationChecker.is_upsert_operation_supported' ) @mock.patch.object(BaseConfigurationResource, "get_operation_specs_by_model_name") @mock.patch.object(BaseConfigurationResource, "_find_object_matching_params") @mock.patch.object(BaseConfigurationResource, "_add_upserted_object") @mock.patch.object(BaseConfigurationResource, "_edit_upserted_object") def test_upsert_object_not_supported(self, edit_mock, add_mock, find_object, get_operation_mock, is_upsert_supported_mock): params = mock.MagicMock() is_upsert_supported_mock.return_value = False self.assertRaises(FtdInvalidOperationNameError, self._resource.upsert_object, 'upsertFoo', params) self._conn.get_model_spec.assert_called_once_with('Foo') get_operation_mock.assert_called_once_with('Foo') is_upsert_supported_mock.assert_called_once_with( get_operation_mock.return_value) find_object.assert_not_called() add_mock.assert_not_called() edit_mock.assert_not_called() @mock.patch( 'ansible_collections.community.network.plugins.module_utils.network.ftd.configuration.OperationChecker.is_upsert_operation_supported' ) @mock.patch.object(BaseConfigurationResource, "get_operation_specs_by_model_name") @mock.patch.object(BaseConfigurationResource, "_find_object_matching_params") @mock.patch.object(BaseConfigurationResource, "_add_upserted_object") @mock.patch.object(BaseConfigurationResource, "_edit_upserted_object") def test_upsert_object_when_model_not_supported(self, edit_mock, add_mock, find_object, get_operation_mock, is_upsert_supported_mock): params = mock.MagicMock() self._conn.get_model_spec.return_value = None self.assertRaises(FtdInvalidOperationNameError, self._resource.upsert_object, 'upsertNonExisting', params) self._conn.get_model_spec.assert_called_once_with('NonExisting') get_operation_mock.assert_not_called() is_upsert_supported_mock.assert_not_called() find_object.assert_not_called() add_mock.assert_not_called() edit_mock.assert_not_called() @mock.patch( 'ansible_collections.community.network.plugins.module_utils.network.ftd.configuration.equal_objects' ) @mock.patch( 'ansible_collections.community.network.plugins.module_utils.network.ftd.configuration.OperationChecker.is_upsert_operation_supported' ) @mock.patch.object(BaseConfigurationResource, "get_operation_specs_by_model_name") @mock.patch.object(BaseConfigurationResource, "_find_object_matching_params") @mock.patch.object(BaseConfigurationResource, "_add_upserted_object") @mock.patch.object(BaseConfigurationResource, "_edit_upserted_object") def test_upsert_object_with_fatal_error_during_edit( self, edit_mock, add_mock, find_object, get_operation_mock, is_upsert_supported_mock, equal_objects_mock): params = mock.MagicMock() existing_obj = mock.MagicMock() is_upsert_supported_mock.return_value = True find_object.return_value = existing_obj equal_objects_mock.return_value = False edit_mock.side_effect = FtdConfigurationError("Some object edit error") self.assertRaises(FtdConfigurationError, self._resource.upsert_object, 'upsertFoo', params) is_upsert_supported_mock.assert_called_once_with( get_operation_mock.return_value) self._conn.get_model_spec.assert_called_once_with('Foo') get_operation_mock.assert_called_once_with('Foo') find_object.assert_called_once_with('Foo', params) add_mock.assert_not_called() edit_mock.assert_called_once_with(get_operation_mock.return_value, existing_obj, params) @mock.patch( 'ansible_collections.community.network.plugins.module_utils.network.ftd.configuration.OperationChecker.is_upsert_operation_supported' ) @mock.patch.object(BaseConfigurationResource, "get_operation_specs_by_model_name") @mock.patch.object(BaseConfigurationResource, "_find_object_matching_params") @mock.patch.object(BaseConfigurationResource, "_add_upserted_object") @mock.patch.object(BaseConfigurationResource, "_edit_upserted_object") def test_upsert_object_with_fatal_error_during_add( self, edit_mock, add_mock, find_object, get_operation_mock, is_upsert_supported_mock): params = mock.MagicMock() is_upsert_supported_mock.return_value = True find_object.return_value = None error = FtdConfigurationError("Obj duplication error") add_mock.side_effect = error self.assertRaises(FtdConfigurationError, self._resource.upsert_object, 'upsertFoo', params) is_upsert_supported_mock.assert_called_once_with( get_operation_mock.return_value) self._conn.get_model_spec.assert_called_once_with('Foo') get_operation_mock.assert_called_once_with('Foo') find_object.assert_called_once_with('Foo', params) add_mock.assert_called_once_with(get_operation_mock.return_value, params) edit_mock.assert_not_called()
def test_get_objects_by_filter_with_multiple_filters( self, send_request_mock, fetch_system_info_mock, connection_mock): objects = [{ 'name': 'obj1', 'type': 1, 'foo': { 'bar': 'buzz' } }, { 'name': 'obj2', 'type': 1, 'foo': { 'bar': 'buz' } }, { 'name': 'obj3', 'type': 2, 'foo': { 'bar': 'buzz' } }] fetch_system_info_mock.return_value = { 'databaseInfo': { 'buildVersion': '6.3.0' } } connection_mock.get_operation_spec.return_value = { 'method': HTTPMethod.GET, 'url': '/object/' } resource = BaseConfigurationResource(connection_mock, False) send_request_mock.side_effect = [{'items': objects}, {'items': []}] # resource.get_objects_by_filter returns generator so to be able compare generated list with expected list # we need evaluate it. assert objects == list(resource.get_objects_by_filter('test', {})) send_request_mock.assert_has_calls( [mock.call('/object/', 'get', {}, {}, { 'limit': 10, 'offset': 0 })]) send_request_mock.reset_mock() send_request_mock.side_effect = [{'items': objects}, {'items': []}] # resource.get_objects_by_filter returns generator so to be able compare generated list with expected list # we need evaluate it. assert [objects[0]] == list( resource.get_objects_by_filter( 'test', {ParamName.FILTERS: { 'name': 'obj1' }})) send_request_mock.assert_has_calls([ mock.call('/object/', 'get', {}, {}, { QueryParams.FILTER: 'name:obj1', 'limit': 10, 'offset': 0 }) ]) send_request_mock.reset_mock() send_request_mock.side_effect = [{'items': objects}, {'items': []}] # resource.get_objects_by_filter returns generator so to be able compare generated list with expected list # we need evaluate it. assert [objects[1]] == list( resource.get_objects_by_filter( 'test', { ParamName.FILTERS: { 'name': 'obj2', 'type': 1, 'foo': { 'bar': 'buz' } } })) send_request_mock.assert_has_calls([ mock.call('/object/', 'get', {}, {}, { QueryParams.FILTER: 'name:obj2', 'limit': 10, 'offset': 0 }) ])
def test_module_should_fail_if_validation_error_in_all_params( self, connection_mock): connection_mock.get_operation_spec.return_value = { 'method': HTTPMethod.POST, 'url': '/test' } report = { 'data': { 'required': ['objects[0].type'], 'invalid_type': [{ 'path': 'objects[3].id', 'expected_type': 'string', 'actually_value': 1 }] }, 'path_params': { 'required': ['some_param'], 'invalid_type': [{ 'path': 'name', 'expected_type': 'string', 'actually_value': True }] }, 'query_params': { 'required': ['other_param'], 'invalid_type': [{ 'path': 'f_integer', 'expected_type': 'integer', 'actually_value': "test" }] } } connection_mock.validate_data.return_value = (False, json.dumps( report['data'], sort_keys=True, indent=4)) connection_mock.validate_query_params.return_value = ( False, json.dumps(report['query_params'], sort_keys=True, indent=4)) connection_mock.validate_path_params.return_value = ( False, json.dumps(report['path_params'], sort_keys=True, indent=4)) with pytest.raises(ValidationError) as e_info: resource = BaseConfigurationResource(connection_mock, False) resource.crud_operation('putTest', {'data': {}}) result = e_info.value.args[0] key_data = 'Invalid data provided' assert result[key_data] result[key_data] = json.loads(result[key_data]) key_path_params = 'Invalid path_params provided' assert result[key_path_params] result[key_path_params] = json.loads(result[key_path_params]) key_query_params = 'Invalid query_params provided' assert result[key_query_params] result[key_query_params] = json.loads(result[key_query_params]) assert result == { key_data: { 'invalid_type': [{ 'actually_value': 1, 'expected_type': 'string', 'path': 'objects[3].id' }], 'required': ['objects[0].type'] }, key_path_params: { 'invalid_type': [{ 'actually_value': True, 'expected_type': 'string', 'path': 'name' }], 'required': ['some_param'] }, key_query_params: { 'invalid_type': [{ 'actually_value': 'test', 'expected_type': 'integer', 'path': 'f_integer' }], 'required': ['other_param'] } }
def test_get_objects_by_filter_with_multiple_responses( self, send_request_mock, fetch_system_info_mock, connection_mock): send_request_mock.side_effect = [{ 'items': [{ 'name': 'obj1', 'type': 'foo' }, { 'name': 'obj2', 'type': 'bar' }] }, { 'items': [{ 'name': 'obj3', 'type': 'foo' }] }, { 'items': [] }] fetch_system_info_mock.return_value = { 'databaseInfo': { 'buildVersion': '6.3.0' } } connection_mock.get_operation_spec.return_value = { 'method': HTTPMethod.GET, 'url': '/object/' } resource = BaseConfigurationResource(connection_mock, False) assert [{ 'name': 'obj1', 'type': 'foo' }] == list( resource.get_objects_by_filter( 'test', {ParamName.FILTERS: { 'type': 'foo' }})) send_request_mock.assert_has_calls( [mock.call('/object/', 'get', {}, {}, { 'limit': 10, 'offset': 0 })]) send_request_mock.reset_mock() send_request_mock.side_effect = [{ 'items': [{ 'name': 'obj1', 'type': 'foo' }, { 'name': 'obj2', 'type': 'bar' }] }, { 'items': [{ 'name': 'obj3', 'type': 'foo' }] }, { 'items': [] }] resp = list( resource.get_objects_by_filter( 'test', { ParamName.FILTERS: { 'type': 'foo' }, ParamName.QUERY_PARAMS: { 'limit': 2 } })) assert [{ 'name': 'obj1', 'type': 'foo' }, { 'name': 'obj3', 'type': 'foo' }] == resp send_request_mock.assert_has_calls([ mock.call('/object/', 'get', {}, {}, { 'limit': 2, 'offset': 0 }), mock.call('/object/', 'get', {}, {}, { 'limit': 2, 'offset': 2 }) ])