diff --git a/lib/ansible/modules/network/eos/eos_eapi.py b/lib/ansible/modules/network/eos/eos_eapi.py index 33e1818b7b..a526b2729b 100644 --- a/lib/ansible/modules/network/eos/eos_eapi.py +++ b/lib/ansible/modules/network/eos/eos_eapi.py @@ -180,6 +180,7 @@ session_name: sample: ansible_1479315771 """ import re +import time from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.eos import run_commands, load_config @@ -205,7 +206,7 @@ def validate_vrf(value, module): if value not in configured_vrfs: module.fail_json(msg='vrf `%s` is not configured on the system' % value) -def map_obj_to_commands(updates, module): +def map_obj_to_commands(updates, module, warnings): commands = list() want, have = updates @@ -220,22 +221,38 @@ def map_obj_to_commands(updates, module): if want['http'] is False: add('no protocol http') else: - port = want['http_port'] or 80 - add('protocol http port %s' % port) + if have['http'] is False and want['http'] in (False, None): + warnings.append('protocol http is not enabled, not configuring http port value') + else: + port = want['http_port'] or 80 + add('protocol http port %s' % port) if any((needs_update('https'), needs_update('https_port'))): if want['https'] is False: add('no protocol https') else: - port = want['https_port'] or 443 - add('protocol https port %s' % port) + if have['https'] is False and want['https'] in (False, None): + warnings.append('protocol https is not enabled, not configuring https port value') + else: + port = want['https_port'] or 443 + add('protocol https port %s' % port) if any((needs_update('local_http'), needs_update('local_http_port'))): if want['local_http'] is False: add('no protocol http localhost') else: - port = want['local_http_port'] or 8080 - add('protocol http localhost port %s' % port) + if have['local_http'] is False and want['local_http'] in (False, None): + warnings.append('protocol local_http is not enabled, not configuring local_http port value') + else: + port = want['local_http_port'] or 8080 + add('protocol http localhost port %s' % port) + + if any((needs_update('socket'), needs_update('socket'))): + if want['socket'] is False: + add('no protocol unix-socket') + else: + add('protocol unix-socket') + if needs_update('vrf'): add('vrf %s' % want['vrf']) @@ -290,6 +307,34 @@ def map_params_to_obj(module): return obj +def verify_state(updates, module): + want, have = updates + + invalid_state = [('http', 'httpServer'), + ('https', 'httpsServer'), + ('local_http', 'localHttpServer'), + ('socket', 'unixSocketServer')] + + timeout = module.params['timeout'] or 30 + state = module.params['state'] + + while invalid_state: + out = run_commands(module, ['show management api http-commands | json']) + for index, item in enumerate(invalid_state): + want_key, eapi_key = item + if want[want_key] is not None: + if want[want_key] == out[0][eapi_key]['running']: + del invalid_state[index] + elif state == 'stopped': + if not out[0][eapi_key]['running']: + del invalid_state[index] + else: + del invalid_state[index] + time.sleep(1) + timeout -= 1 + if timeout == 0: + module.fail_json(msg='timeout expired before eapi running state changed') + def collect_facts(module, result): out = run_commands(module, ['show management api http-commands | json']) facts = dict(eos_eapi_urls=dict()) @@ -318,6 +363,7 @@ def main(): vrf=dict(default='default'), + config=dict(), state=dict(default='started', choices=['stopped', 'started']), ) @@ -326,12 +372,17 @@ def main(): module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + result = {'changed': False} + warnings = list() + if module.params['config']: + warnings.append('config parameter is no longer necessary and will be ignored') + want = map_params_to_obj(module) have = map_config_to_obj(module) - commands = map_obj_to_commands((want, have), module) + commands = map_obj_to_commands((want, have), module, warnings) result['commands'] = commands if commands: @@ -342,8 +393,14 @@ def main(): result['session_name'] = response.get('session') result['changed'] = True + if result['changed']: + verify_state((want, have), module) + collect_facts(module, result) + if warnings: + result['warnings'] = warnings + module.exit_json(**result) diff --git a/test/integration/targets/eos_eapi/tests/cli/badtransport.yaml b/test/integration/targets/eos_eapi/tests/cli/badtransport.1 similarity index 100% rename from test/integration/targets/eos_eapi/tests/cli/badtransport.yaml rename to test/integration/targets/eos_eapi/tests/cli/badtransport.1 diff --git a/test/integration/targets/eos_eapi/tests/cli/configure.yaml b/test/integration/targets/eos_eapi/tests/cli/configure.yaml index 27c29f1190..3f32f4dfc7 100644 --- a/test/integration/targets/eos_eapi/tests/cli/configure.yaml +++ b/test/integration/targets/eos_eapi/tests/cli/configure.yaml @@ -21,13 +21,13 @@ - name: Expect endpoint ports to be set assert: that: - - http_config.stdout[0].httpServer.port == 81 + - http_config.stdout[0].httpServer.port == 80 - http_config.stdout[0].httpsServer.port == 4443 - http_config.stdout[0].localHttpServer.port == 8181 - name: Change endpoint ports again eos_eapi: - http_port: 81 + http_port: 80 https_port: 4443 enable_local_http: yes local_http_port: 8181 diff --git a/test/integration/targets/eos_eapi/tests/cli/vrf.yaml b/test/integration/targets/eos_eapi/tests/cli/vrf.yaml index b21387fb2d..e71f5e38b1 100644 --- a/test/integration/targets/eos_eapi/tests/cli/vrf.yaml +++ b/test/integration/targets/eos_eapi/tests/cli/vrf.yaml @@ -15,7 +15,7 @@ that: - "eos_eapi_output.failed == true" - "eos_eapi_output.changed == false" - - eos_eapi_output.msg == "vrf 'foobar' is not configured" + - eos_eapi_output.msg == "vrf `foobar` is not configured on the system" #---- - name: Set VRF to default diff --git a/test/integration/targets/eos_eapi/tests/cli/zzz_reset.yaml b/test/integration/targets/eos_eapi/tests/cli/zzz_reset.1 similarity index 84% rename from test/integration/targets/eos_eapi/tests/cli/zzz_reset.yaml rename to test/integration/targets/eos_eapi/tests/cli/zzz_reset.1 index a11afef7c2..b489ae80fc 100644 --- a/test/integration/targets/eos_eapi/tests/cli/zzz_reset.yaml +++ b/test/integration/targets/eos_eapi/tests/cli/zzz_reset.1 @@ -1,8 +1,9 @@ - debug: msg="START CLI/RESET.YAML" - name: Change endpoint ports back to default values - eos_eapi: - enable_local_http: yes + eos_config: + lines: default management api http-commands + match: none provider: "{{ cli }}" register: eos_eapi_output connection: local @@ -22,8 +23,9 @@ - http_config.stdout[0].localHttpServer.port == 8080 - name: Change endpoint ports back to default values again - eos_eapi: - enable_local_http: yes + eos_config: + lines: default management api http-commands + match: none provider: "{{ cli }}" register: eos_eapi_output connection: local diff --git a/test/units/modules/network/eos/test_eos_eapi.py b/test/units/modules/network/eos/test_eos_eapi.py index c5b659171a..a55ccebf8f 100644 --- a/test/units/modules/network/eos/test_eos_eapi.py +++ b/test/units/modules/network/eos/test_eos_eapi.py @@ -39,12 +39,22 @@ class TestEosEapiModule(TestEosModule): self.mock_load_config = patch('ansible.modules.network.eos.eos_eapi.load_config') self.load_config = self.mock_load_config.start() + self.mock_verify_state = patch('ansible.modules.network.eos.eos_eapi.verify_state') + self.verify_state = self.mock_verify_state.start() + self.command_fixtures = {} def tearDown(self): self.mock_run_commands.stop() self.mock_load_config.stop() + # hack for older version of mock + # should be using patch.stopall() but CI is still failing + try: + self.mock_verify_state.stop() + except RuntimeError: + pass + def load_fixtures(self, commands=None): def run_commands(module, commands, **kwargs): output = list() @@ -137,3 +147,14 @@ class TestEosEapiModule(TestEosModule): commands = ['management api http-commands', 'shutdown'] self.start_configured(changed=True, commands=commands) + def test_eos_eapi_state_failed(self): + self.mock_verify_state.stop() + set_module_args(dict(state='stopped', timeout=1)) + result = self.start_configured(failed=True) + 'timeout expired before eapi running state changed' in result['msg'] + + def test_eos_eapi_state_failed(self): + self.mock_verify_state.stop() + set_module_args(dict(state='stopped', timeout=1)) + result = self.start_configured(failed=True) + 'timeout expired before eapi running state changed' in result['msg']