From 80b0e11ee13d5a3aedd65002a64fe2ae00976ae2 Mon Sep 17 00:00:00 2001 From: antoni Date: Fri, 8 Dec 2017 14:00:17 +0100 Subject: [PATCH 1/8] Refactor of ip address to use the idempotent class. Additional test to edit address --- library/mt_ip_address.py | 191 +++++++------------- tests/integration/tasks/test-ip-address.yml | 53 ++++-- 2 files changed, 104 insertions(+), 140 deletions(-) diff --git a/library/mt_ip_address.py b/library/mt_ip_address.py index 17fd421..bb5a384 100644 --- a/library/mt_ip_address.py +++ b/library/mt_ip_address.py @@ -3,38 +3,34 @@ module: mt_ip_address author: - "Valentin Gurmeza" - "Shaun Smiley" + - "Antoni Matamalas" version_added: "2.3" short_description: Manage mikrotik /ip/addresses requirements: - - rosapi + - mt_api description: - - FILL ME OUT + - Manage addresses on interfaces options: hostname: description: - - + - hotstname of mikrotik router + required: True username: description: - - + - username used to connect to mikrotik router + required: True password: description: - - - interface: + - password used for authentication to mikrotik router + required: True + settings: description: - - - address: - description: - - - network: - description: - - + - All Mikrotik compatible parameters for this particular endpoint. + Any yes/no values must be enclosed in double quotes + required: True state: description: - - - force: - description: - - True/False value to force removing the address on an interface - even if the address does not match. + - absent or present ''' EXAMPLES = ''' @@ -42,18 +38,15 @@ EXAMPLES = ''' hostname: "{{ inventory_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" - interface: "ether2" - address: "192.168.88.2/24" - network: "192.168.88.0/24" - state: "present" - comment: "link 3" + settings: + interface: "ether2" + address: "192.168.88.2/24" + network: "192.168.88.0/24" + state: "present" + comment: "link 3" ''' -from ansible.module_utils import mt_api -import socket - -#import mt_action #TODO: get this working - +from ansible.module_utils.mt_common import clean_params, MikrotikIdempotent from ansible.module_utils.basic import AnsibleModule @@ -64,120 +57,62 @@ def main(): hostname = dict(required=True), username = dict(required=True), password = dict(required=True), - interface = dict(required=True, type='str'), - address = dict(required=True, type='str', aliases=['ip', 'addr', 'ip_address']), - network = dict(required=False, type='str', default=""), - comment = dict(required=False, type='str', default=""), + settings = dict(required=False, type='dict'), state = dict( required = False, default = "present", choices = ['present', 'absent'], type = 'str' ), - ) + ), + supports_check_mode=True ) - hostname = module.params['hostname'] - username = module.params['username'] - password = module.params['password'] - ip_address = module.params['address'] - interface = module.params['interface'] - network = module.params['network'] - ip_state = module.params['state'] - comment = module.params['comment'] - changed = False - msg = "" + idempotent_parameter = None + params = module.params + idempotent_parameter = 'interface' + mt_obj = MikrotikIdempotent( + hostname = params['hostname'], + username = params['username'], + password = params['password'], + state = params['state'], + desired_params = params['settings'], + idempotent_param = idempotent_parameter, + api_path = '/ip/address', + check_mode = module.check_mode + ) - interface_path = '/interface' - address_path = '/ip/address' - address_print_params = { - ".proplist": "interface,address,.id,network,netmask,comment" - } - interface_print_params = { - ".proplist": "name,.id,type" - } - mk = mt_api.Mikrotik(hostname,username,password) - try: - mk.login() - interfaces = mk.api_print(interface_path, interface_print_params) - except: + # exit if login failed + if not mt_obj.login_success: module.fail_json( - msg="Could not log into Mikrotik device." + - " Check the username and password.", + msg = mt_obj.failed_msg ) - ################################### - # Check if interface is present - # exit if interface is not present - ################################### - interfacelist = [] - exitmessage = [] - for i in range(0, len(interfaces) - 1): - interfacelist.append(interfaces[i][1]["name"]) - intExists = False + # add, remove or edit things + mt_obj.sync_state() - if (interface in interfacelist): - intExists = True - # module.exit_json(failed=False, changed=False, msg=interfacelist) - if intExists: - pass - #exitmessage.append("Interface " + interface + " exists.") #this is never used + if mt_obj.failed: + module.fail_json( + msg = mt_obj.failed_msg + ) + elif mt_obj.changed: + module.exit_json( + failed=False, + changed=True, + msg=mt_obj.changed_msg, + diff={ "prepared": { + "old": mt_obj.old_params, + "new": mt_obj.new_params, + }}, + ) else: - exitmessage.append("Interface " + interface + " does not exist.") - module.fail_json(failed=True, msg=exitmessage) - - ############################################## - # Check if IP address is set on the interface - # make no changes if address already set - ############################################## - ip_addresses = mk.api_print(address_path, address_print_params) - - iplist = [] - for i in range(0, len(ip_addresses) - 1): - iplist.append(ip_addresses[i][1]["address"]) - if ip_addresses[i][1]["address"] == ip_address: - ip_id = ip_addresses[i][1][".id"] - - if ip_state == "present": - if ip_address in iplist: - module.exit_json( - failed=False, - #msg="IP Address: " + ip_address + - #" is already configured" + - #" on interface " + interface, - ) - - else: - add_dict = { - 'address': ip_address, - 'interface': interface, - 'comment': comment - } - response = mk.api_add(address_path, add_dict) - module.exit_json( - failed=False, - changed=True, - #msg="IP address: " + ip_address + " has been configured" + - #" on interface " + interface - ) - - if ip_state == "absent": - if ip_address in iplist: - response = mk.api_remove(address_path, ip_id) - module.exit_json( - failed=False, - changed=True, - #msg="IP Address: " + ip_address + - #" has been removed" - ) - - else: - module.exit_json( - failed=False, - changed=False, - #msg="IP Address: " + ip_address + - #" is already absent" - ) + module.exit_json( + failed=False, + changed=False, + #msg='', + msg=params['settings'], + ) if __name__ == '__main__': main() + diff --git a/tests/integration/tasks/test-ip-address.yml b/tests/integration/tasks/test-ip-address.yml index 48ea95d..52c2003 100644 --- a/tests/integration/tasks/test-ip-address.yml +++ b/tests/integration/tasks/test-ip-address.yml @@ -5,21 +5,36 @@ username: "{{ mt_user }}" password: "{{ mt_pass }}" state: "present" - interface: "ether2" - address: "192.168.88.2/24" - network: "192.168.88.0" + settings: + interface: "ether2" + address: "192.168.88.2/24" + network: "192.168.88.0" register: ip_addr_add_2 failed_when: not ( ip_addr_add_2 | changed ) +- name: NEVER_CHANGES Test adding the same ip addr again to ether2 + mt_ip_address: + hostname: "{{ mt_hostname }}" + username: "{{ mt_user }}" + password: "{{ mt_pass }}" + state: "present" + settings: + interface: "ether2" + address: "192.168.88.2/24" + network: "192.168.88.0" + register: ip_addr_add_2 + failed_when: ip_addr_add_2 | changed + - name: Test adding an ip addr with comment ether3 mt_ip_address: hostname: "{{ mt_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" state: "present" - interface: "ether3" - address: "192.168.88.3/24" - comment: "interface #3!!!" + settings: + interface: "ether3" + address: "192.168.88.3/24" + comment: "interface #3!!!" - name: Test adding an ip addr with comment and network ether4 mt_ip_address: @@ -27,10 +42,23 @@ username: "{{ mt_user }}" password: "{{ mt_pass }}" state: "present" - interface: "ether4" - address: "192.168.88.4/24" - network: "192.168.88.0" - comment: "interface #4!!!" + settings: + interface: "ether4" + address: "192.168.88.4/24" + network: "192.168.88.0" + comment: "interface #4!!!" + +- name: Test changing an ip addr with comment and network ether4 + mt_ip_address: + hostname: "{{ mt_hostname }}" + username: "{{ mt_user }}" + password: "{{ mt_pass }}" + state: "present" + settings: + interface: "ether4" + address: "192.168.88.5/24" + network: "192.168.88.0" + comment: "interface #4 new address!!!" - name: ALWAYS_CHANGES Test removing ip addr ether2 mt_ip_address: @@ -38,7 +66,8 @@ username: "{{ mt_user }}" password: "{{ mt_pass }}" state: "absent" - interface: "ether2" - address: "192.168.88.2/24" + settings: + interface: "ether2" + address: "192.168.88.2/24" register: ip_addr_rem_2 failed_when: not ( ip_addr_rem_2 | changed ) From 16644918319b9410d7eba40c5e8e7ada580f772e Mon Sep 17 00:00:00 2001 From: antoni Date: Fri, 8 Dec 2017 14:00:17 +0100 Subject: [PATCH 2/8] Refactor of ip address to use the idempotent class. Additional test to edit address --- library/mt_ip_address.py | 191 +++++++------------- tests/integration/tasks/test-ip-address.yml | 57 ++++-- 2 files changed, 106 insertions(+), 142 deletions(-) diff --git a/library/mt_ip_address.py b/library/mt_ip_address.py index f42afa3..b191da0 100644 --- a/library/mt_ip_address.py +++ b/library/mt_ip_address.py @@ -3,38 +3,34 @@ module: mt_ip_address author: - "Valentin Gurmeza" - "Shaun Smiley" + - "Antoni Matamalas" version_added: "2.3" short_description: Manage mikrotik /ip/addresses requirements: - - rosapi + - mt_api description: - - FILL ME OUT + - Manage addresses on interfaces options: hostname: description: - - + - hotstname of mikrotik router + required: True username: description: - - + - username used to connect to mikrotik router + required: True password: description: - - - interface: + - password used for authentication to mikrotik router + required: True + settings: description: - - - address: - description: - - - network: - description: - - + - All Mikrotik compatible parameters for this particular endpoint. + Any yes/no values must be enclosed in double quotes + required: True state: description: - - - force: - description: - - True/False value to force removing the address on an interface - even if the address does not match. + - absent or present ''' EXAMPLES = ''' @@ -42,18 +38,15 @@ EXAMPLES = ''' hostname: "{{ inventory_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" - interface: "ether2" - address: "192.168.88.2/24" - network: "192.168.88.0/24" - state: "present" - comment: "link 3" + settings: + interface: "ether2" + address: "192.168.88.2/24" + network: "192.168.88.0/24" + state: "present" + comment: "link 3" ''' -from ansible.module_utils import mt_api -import socket - -#import mt_action #TODO: get this working - +from ansible.module_utils.mt_common import clean_params, MikrotikIdempotent from ansible.module_utils.basic import AnsibleModule @@ -64,120 +57,62 @@ def main(): hostname = dict(required=True), username = dict(required=True), password = dict(required=True, no_log=True), - interface = dict(required=True, type='str'), - address = dict(required=True, type='str', aliases=['ip', 'addr', 'ip_address']), - network = dict(required=False, type='str', default=""), - comment = dict(required=False, type='str', default=""), + settings = dict(required=False, type='dict'), state = dict( required = False, default = "present", choices = ['present', 'absent'], type = 'str' ), - ) + ), + supports_check_mode=True ) - hostname = module.params['hostname'] - username = module.params['username'] - password = module.params['password'] - ip_address = module.params['address'] - interface = module.params['interface'] - network = module.params['network'] - ip_state = module.params['state'] - comment = module.params['comment'] - changed = False - msg = "" + idempotent_parameter = None + params = module.params + idempotent_parameter = 'interface' + mt_obj = MikrotikIdempotent( + hostname = params['hostname'], + username = params['username'], + password = params['password'], + state = params['state'], + desired_params = params['settings'], + idempotent_param = idempotent_parameter, + api_path = '/ip/address', + check_mode = module.check_mode + ) - interface_path = '/interface' - address_path = '/ip/address' - address_print_params = { - ".proplist": "interface,address,.id,network,netmask,comment" - } - interface_print_params = { - ".proplist": "name,.id,type" - } - mk = mt_api.Mikrotik(hostname,username,password) - try: - mk.login() - interfaces = mk.api_print(interface_path, interface_print_params) - except: + # exit if login failed + if not mt_obj.login_success: module.fail_json( - msg="Could not log into Mikrotik device." + - " Check the username and password.", + msg = mt_obj.failed_msg ) - ################################### - # Check if interface is present - # exit if interface is not present - ################################### - interfacelist = [] - exitmessage = [] - for i in range(0, len(interfaces) - 1): - interfacelist.append(interfaces[i][1]["name"]) - intExists = False + # add, remove or edit things + mt_obj.sync_state() - if (interface in interfacelist): - intExists = True - # module.exit_json(failed=False, changed=False, msg=interfacelist) - if intExists: - pass - #exitmessage.append("Interface " + interface + " exists.") #this is never used + if mt_obj.failed: + module.fail_json( + msg = mt_obj.failed_msg + ) + elif mt_obj.changed: + module.exit_json( + failed=False, + changed=True, + msg=mt_obj.changed_msg, + diff={ "prepared": { + "old": mt_obj.old_params, + "new": mt_obj.new_params, + }}, + ) else: - exitmessage.append("Interface " + interface + " does not exist.") - module.fail_json(failed=True, msg=exitmessage) - - ############################################## - # Check if IP address is set on the interface - # make no changes if address already set - ############################################## - ip_addresses = mk.api_print(address_path, address_print_params) - - iplist = [] - for i in range(0, len(ip_addresses) - 1): - iplist.append(ip_addresses[i][1]["address"]) - if ip_addresses[i][1]["address"] == ip_address: - ip_id = ip_addresses[i][1][".id"] - - if ip_state == "present": - if ip_address in iplist: - module.exit_json( - failed=False, - #msg="IP Address: " + ip_address + - #" is already configured" + - #" on interface " + interface, - ) - - else: - add_dict = { - 'address': ip_address, - 'interface': interface, - 'comment': comment - } - response = mk.api_add(address_path, add_dict) - module.exit_json( - failed=False, - changed=True, - #msg="IP address: " + ip_address + " has been configured" + - #" on interface " + interface - ) - - if ip_state == "absent": - if ip_address in iplist: - response = mk.api_remove(address_path, ip_id) - module.exit_json( - failed=False, - changed=True, - #msg="IP Address: " + ip_address + - #" has been removed" - ) - - else: - module.exit_json( - failed=False, - changed=False, - #msg="IP Address: " + ip_address + - #" is already absent" - ) + module.exit_json( + failed=False, + changed=False, + #msg='', + msg=params['settings'], + ) if __name__ == '__main__': main() + diff --git a/tests/integration/tasks/test-ip-address.yml b/tests/integration/tasks/test-ip-address.yml index 981324c..0d78a6d 100644 --- a/tests/integration/tasks/test-ip-address.yml +++ b/tests/integration/tasks/test-ip-address.yml @@ -22,32 +22,60 @@ username: "{{ mt_user }}" password: "{{ mt_pass }}" state: "present" - interface: "ether2" - address: "192.168.88.2/24" - network: "192.168.88.0" + settings: + interface: "ether2" + address: "192.168.88.2/24" + network: "192.168.88.0" register: ip_addr_add_2 failed_when: not ( ip_addr_add_2 | changed ) -- name: Test adding an ip addr with comment bridge2 +- name: NEVER_CHANGES Test adding the same ip addr again to ether2 mt_ip_address: hostname: "{{ mt_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" state: "present" - interface: "bridge2" - address: "192.168.88.3/24" - comment: "bridge #2!!!" + settings: + interface: "ether2" + address: "192.168.88.2/24" + network: "192.168.88.0" + register: ip_addr_add_2 + failed_when: ip_addr_add_2 | changed -- name: Test adding an ip addr with comment and network bridge3 +- name: Test adding an ip addr with comment ether3 mt_ip_address: hostname: "{{ mt_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" state: "present" - interface: "bridge3" - address: "192.168.88.4/24" - network: "192.168.88.0" - comment: "bridge #3!!!" + settings: + interface: "ether3" + address: "192.168.88.3/24" + comment: "interface #3!!!" + +- name: Test adding an ip addr with comment and network ether4 + mt_ip_address: + hostname: "{{ mt_hostname }}" + username: "{{ mt_user }}" + password: "{{ mt_pass }}" + state: "present" + settings: + interface: "ether4" + address: "192.168.88.4/24" + network: "192.168.88.0" + comment: "interface #4!!!" + +- name: Test changing an ip addr with comment and network ether4 + mt_ip_address: + hostname: "{{ mt_hostname }}" + username: "{{ mt_user }}" + password: "{{ mt_pass }}" + state: "present" + settings: + interface: "ether4" + address: "192.168.88.5/24" + network: "192.168.88.0" + comment: "interface #4 new address!!!" - name: ALWAYS_CHANGES Test removing ip addr ether2 mt_ip_address: @@ -55,7 +83,8 @@ username: "{{ mt_user }}" password: "{{ mt_pass }}" state: "absent" - interface: "ether2" - address: "192.168.88.2/24" + settings: + interface: "ether2" + address: "192.168.88.2/24" register: ip_addr_rem_2 failed_when: not ( ip_addr_rem_2 | changed ) From 579ce84db38def7da4556c0c147b2cbf7547b8aa Mon Sep 17 00:00:00 2001 From: antoni Date: Sat, 24 Feb 2018 18:53:38 +0100 Subject: [PATCH 3/8] Improved testing for ip address module --- tests/integration/tasks/test-ip-address.yml | 30 ++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/tests/integration/tasks/test-ip-address.yml b/tests/integration/tasks/test-ip-address.yml index 0d78a6d..1d95cfe 100644 --- a/tests/integration/tasks/test-ip-address.yml +++ b/tests/integration/tasks/test-ip-address.yml @@ -63,9 +63,9 @@ interface: "ether4" address: "192.168.88.4/24" network: "192.168.88.0" - comment: "interface #4!!!" + comment: "interface #4 first addition" -- name: Test changing an ip addr with comment and network ether4 +- name: Test adding a second ip addr with comment and network ether4 mt_ip_address: hostname: "{{ mt_hostname }}" username: "{{ mt_user }}" @@ -75,7 +75,7 @@ interface: "ether4" address: "192.168.88.5/24" network: "192.168.88.0" - comment: "interface #4 new address!!!" + comment: "interface #4 second addition" - name: ALWAYS_CHANGES Test removing ip addr ether2 mt_ip_address: @@ -88,3 +88,27 @@ address: "192.168.88.2/24" register: ip_addr_rem_2 failed_when: not ( ip_addr_rem_2 | changed ) + +- name: NEVER_CHANGES Test removing ip addr ether2 again + mt_ip_address: + hostname: "{{ mt_hostname }}" + username: "{{ mt_user }}" + password: "{{ mt_pass }}" + state: "absent" + settings: + interface: "ether2" + address: "192.168.88.2/24" + register: ip_addr_rem_2 + failed_when: ip_addr_rem_2 | changed + +- name: ALWAYS_CHANGES Test removing an ip addr from ether4 + mt_ip_address: + hostname: "{{ mt_hostname }}" + username: "{{ mt_user }}" + password: "{{ mt_pass }}" + state: "absent" + settings: + interface: "ether4" + address: "192.168.88.4/24" + register: ip_addr_rem_4 + failed_when: not (ip_addr_rem_4 | changed ) From 4ebf1ca73058d7af6a0ec8df248bdd531d1662f0 Mon Sep 17 00:00:00 2001 From: antoni Date: Sat, 24 Feb 2018 19:06:22 +0100 Subject: [PATCH 4/8] changed the idempotent parameter to address to have the correct behavior --- library/mt_ip_address.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/mt_ip_address.py b/library/mt_ip_address.py index b191da0..59eb8d1 100644 --- a/library/mt_ip_address.py +++ b/library/mt_ip_address.py @@ -70,7 +70,7 @@ def main(): idempotent_parameter = None params = module.params - idempotent_parameter = 'interface' + idempotent_parameter = 'address' mt_obj = MikrotikIdempotent( hostname = params['hostname'], username = params['username'], From 6061e1d8518d8a84fcda9433d06f1e696185d8b8 Mon Sep 17 00:00:00 2001 From: antoni Date: Mon, 5 Mar 2018 20:46:13 +0100 Subject: [PATCH 5/8] Fixed testing using bridges and not ethernet interfaces --- tests/integration/tasks/test-ip-address.yml | 38 ++++++++++----------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/tests/integration/tasks/test-ip-address.yml b/tests/integration/tasks/test-ip-address.yml index 1d95cfe..809c622 100644 --- a/tests/integration/tasks/test-ip-address.yml +++ b/tests/integration/tasks/test-ip-address.yml @@ -16,99 +16,99 @@ - "bridge3" - "bridge4" -- name: ALWAYS_CHANGES Test adding an ip addr ether2 +- name: ALWAYS_CHANGES Test adding an ip addr bridge2 mt_ip_address: hostname: "{{ mt_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" state: "present" settings: - interface: "ether2" + interface: "bridge2" address: "192.168.88.2/24" network: "192.168.88.0" register: ip_addr_add_2 failed_when: not ( ip_addr_add_2 | changed ) -- name: NEVER_CHANGES Test adding the same ip addr again to ether2 +- name: NEVER_CHANGES Test adding the same ip addr again to bridge2 mt_ip_address: hostname: "{{ mt_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" state: "present" settings: - interface: "ether2" + interface: "bridge2" address: "192.168.88.2/24" network: "192.168.88.0" register: ip_addr_add_2 failed_when: ip_addr_add_2 | changed -- name: Test adding an ip addr with comment ether3 +- name: Test adding an ip addr with comment bridge3 mt_ip_address: hostname: "{{ mt_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" state: "present" settings: - interface: "ether3" + interface: "bridge3" address: "192.168.88.3/24" - comment: "interface #3!!!" + comment: "bridge #3!!!" -- name: Test adding an ip addr with comment and network ether4 +- name: Test adding an ip addr with comment and network bridge4 mt_ip_address: hostname: "{{ mt_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" state: "present" settings: - interface: "ether4" + interface: "bridge4" address: "192.168.88.4/24" network: "192.168.88.0" - comment: "interface #4 first addition" + comment: "bridge4 first addition" -- name: Test adding a second ip addr with comment and network ether4 +- name: Test adding a second ip addr with comment and network bridge4 mt_ip_address: hostname: "{{ mt_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" state: "present" settings: - interface: "ether4" + interface: "bridge4" address: "192.168.88.5/24" network: "192.168.88.0" - comment: "interface #4 second addition" + comment: "bridge #4 second addition" -- name: ALWAYS_CHANGES Test removing ip addr ether2 +- name: ALWAYS_CHANGES Test removing ip addr bridge2 mt_ip_address: hostname: "{{ mt_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" state: "absent" settings: - interface: "ether2" + interface: "bridge2" address: "192.168.88.2/24" register: ip_addr_rem_2 failed_when: not ( ip_addr_rem_2 | changed ) -- name: NEVER_CHANGES Test removing ip addr ether2 again +- name: NEVER_CHANGES Test removing ip addr bridge2 again mt_ip_address: hostname: "{{ mt_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" state: "absent" settings: - interface: "ether2" + interface: "bridge2" address: "192.168.88.2/24" register: ip_addr_rem_2 failed_when: ip_addr_rem_2 | changed -- name: ALWAYS_CHANGES Test removing an ip addr from ether4 +- name: ALWAYS_CHANGES Test removing an ip addr from bridge4 mt_ip_address: hostname: "{{ mt_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" state: "absent" settings: - interface: "ether4" + interface: "bridge4" address: "192.168.88.4/24" register: ip_addr_rem_4 failed_when: not (ip_addr_rem_4 | changed ) From b278045311ebea80433e1d1d1bc57056103ee5c6 Mon Sep 17 00:00:00 2001 From: antoni Date: Mon, 5 Mar 2018 20:46:45 +0100 Subject: [PATCH 6/8] Corrected error with the idempotent parameter which must be address and not interface --- library/mt_ip_address.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/mt_ip_address.py b/library/mt_ip_address.py index b191da0..59eb8d1 100644 --- a/library/mt_ip_address.py +++ b/library/mt_ip_address.py @@ -70,7 +70,7 @@ def main(): idempotent_parameter = None params = module.params - idempotent_parameter = 'interface' + idempotent_parameter = 'address' mt_obj = MikrotikIdempotent( hostname = params['hostname'], username = params['username'], From 3cec44d45117ca3f850c3bbf551c0ce9f48dae35 Mon Sep 17 00:00:00 2001 From: antoni Date: Mon, 5 Mar 2018 20:57:43 +0100 Subject: [PATCH 7/8] Improved testing adding some verification tasks --- tests/integration/tasks/test-ip-address.yml | 25 +++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/integration/tasks/test-ip-address.yml b/tests/integration/tasks/test-ip-address.yml index 809c622..7401986 100644 --- a/tests/integration/tasks/test-ip-address.yml +++ b/tests/integration/tasks/test-ip-address.yml @@ -112,3 +112,28 @@ address: "192.168.88.4/24" register: ip_addr_rem_4 failed_when: not (ip_addr_rem_4 | changed ) + +- name: NEVER_CHANGES Verify ip addr from bridge4 has been removed + mt_ip_address: + hostname: "{{ mt_hostname }}" + username: "{{ mt_user }}" + password: "{{ mt_pass }}" + state: "absent" + settings: + interface: "bridge4" + address: "192.168.88.4/24" + register: ip_addr_rem_4 + failed_when: ip_addr_rem_4 | changed + +- name: NEVER_CHANGES Verify that we have the right ip address in bridge4 + mt_ip_address: + hostname: "{{ mt_hostname }}" + username: "{{ mt_user }}" + password: "{{ mt_pass }}" + state: "present" + settings: + interface: "bridge4" + address: "192.168.88.5/24" + register: ip_addr_rem_4 + failed_when: ip_addr_rem_4 | changed + From 1111a04f734f1edcdad7286c41f756b40e2bf57f Mon Sep 17 00:00:00 2001 From: antoni Date: Sun, 11 Mar 2018 19:30:19 +0100 Subject: [PATCH 8/8] Added option for idempotent parameter to allow the user to control behavior of the module --- library/mt_ip_address.py | 59 ++++++++- tests/integration/tasks/test-ip-address.yml | 131 ++++++++++++++++++++ 2 files changed, 184 insertions(+), 6 deletions(-) diff --git a/library/mt_ip_address.py b/library/mt_ip_address.py index 59eb8d1..e75ed4e 100644 --- a/library/mt_ip_address.py +++ b/library/mt_ip_address.py @@ -23,6 +23,19 @@ options: description: - password used for authentication to mikrotik router required: True + idempotent: + description: + - parameter that will define the behavior for the ip address status. + - If "interface" is used, only one IP will be allowed per interface. + The "state" parameter will define if the IP is added, edited or + removed. No settings options are required to removed the IP from an + interface + - If "address" is used, and interface will be able to have multiple IPs, + but address will only be added or removed. In order to change an IP, it + will have to be first removed and then added to the interface in two + tasks. + required: False + default: address settings: description: - All Mikrotik compatible parameters for this particular endpoint. @@ -30,20 +43,50 @@ options: required: True state: description: - - absent or present + - Depending on the idempotent option, it will define the status of the IP + on an interface + required: False + default: present ''' EXAMPLES = ''' +# Add IP to an interface with a comment. If the interface has already an IP it +# will add as a sencond IP - mt_ip_address: hostname: "{{ inventory_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" + idempotent: "address" + state: "present" settings: interface: "ether2" address: "192.168.88.2/24" network: "192.168.88.0/24" - state: "present" comment: "link 3" + +# Assign IP to the interface. If the interface has any previous IP, it will be +# replaced by this one. +- mt_ip_address: + hostname: "{{ inventory_hostname }}" + username: "{{ mt_user }}" + password: "{{ mt_pass }}" + idempotent: "interface" + state: "present" + settings: + interface: "ether2" + address: "192.168.88.2/24" + network: "192.168.88.0/24" + comment: "link 3" + +# Remove any IP from an interface +- mt_ip_address: + hostname: "{{ inventory_hostname }}" + username: "{{ mt_user }}" + password: "{{ mt_pass }}" + idempotent: "interface" + state: "absent" + settings: + interface: "ether2" ''' from ansible.module_utils.mt_common import clean_params, MikrotikIdempotent @@ -57,7 +100,13 @@ def main(): hostname = dict(required=True), username = dict(required=True), password = dict(required=True, no_log=True), - settings = dict(required=False, type='dict'), + settings = dict(required=True, type='dict'), + idempotent = dict( + required = False, + default = 'address', + choices = ['address', 'interface'], + type = 'str' + ), state = dict( required = False, default = "present", @@ -68,16 +117,14 @@ def main(): supports_check_mode=True ) - idempotent_parameter = None params = module.params - idempotent_parameter = 'address' mt_obj = MikrotikIdempotent( hostname = params['hostname'], username = params['username'], password = params['password'], state = params['state'], desired_params = params['settings'], - idempotent_param = idempotent_parameter, + idempotent_param = params['idempotent'], api_path = '/ip/address', check_mode = module.check_mode ) diff --git a/tests/integration/tasks/test-ip-address.yml b/tests/integration/tasks/test-ip-address.yml index 7401986..fda8be2 100644 --- a/tests/integration/tasks/test-ip-address.yml +++ b/tests/integration/tasks/test-ip-address.yml @@ -16,6 +16,21 @@ - "bridge3" - "bridge4" +- name: Remove any ip from bridge interfaces + mt_ip_address: + hostname: "{{ mt_hostname }}" + username: "{{ mt_user }}" + password: "{{ mt_pass }}" + state: absent + idempotent: interface + settings: + interface: "{{ item }}" + with_items: + - "bridge1" + - "bridge2" + - "bridge3" + - "bridge4" + - name: ALWAYS_CHANGES Test adding an ip addr bridge2 mt_ip_address: hostname: "{{ mt_hostname }}" @@ -137,3 +152,119 @@ register: ip_addr_rem_4 failed_when: ip_addr_rem_4 | changed +- name: Remove any IP from bridge interfaces + mt_ip_address: + hostname: "{{ mt_hostname }}" + username: "{{ mt_user }}" + password: "{{ mt_pass }}" + state: absent + idempotent: interface + settings: + interface: "{{ item }}" + with_items: + - "bridge1" + - "bridge2" + - "bridge3" + - "bridge4" + +- name: ALWAYS_CHANGES Add ip using idempotent interface on bridge2 + mt_ip_address: + hostname: "{{ mt_hostname }}" + username: "{{ mt_user }}" + password: "{{ mt_pass }}" + state: "present" + idempotent: "interface" + settings: + interface: "bridge2" + address: "192.168.89.2/24" + register: ip_addr_rem_2 + failed_when: not (ip_addr_rem_2 | changed) + +- name: NEVER_CHANGES Add AGAIN ip using idempotent interface on bridge2 + mt_ip_address: + hostname: "{{ mt_hostname }}" + username: "{{ mt_user }}" + password: "{{ mt_pass }}" + state: "present" + idempotent: "interface" + settings: + interface: "bridge2" + address: "192.168.89.2/24" + register: ip_addr_rem_2 + failed_when: ip_addr_rem_2 | changed + +- name: ALWAYS_CHANGES Add ip using idempotent interface on bridge3 + mt_ip_address: + hostname: "{{ mt_hostname }}" + username: "{{ mt_user }}" + password: "{{ mt_pass }}" + state: "present" + idempotent: "interface" + settings: + interface: "bridge3" + address: "192.168.89.3/24" + register: ip_addr_rem_3 + failed_when: not (ip_addr_rem_3 | changed) + +- name: ALWAYS_CHANGES Remove ip using idempotent interface on bridge3 + mt_ip_address: + hostname: "{{ mt_hostname }}" + username: "{{ mt_user }}" + password: "{{ mt_pass }}" + state: "absent" + idempotent: "interface" + settings: + interface: "bridge3" + register: ip_addr_rem_3 + failed_when: not (ip_addr_rem_3 | changed) + +- name: NEVER_CHANGES Remove ip AGAIN using idempotent interface on bridge3 + mt_ip_address: + hostname: "{{ mt_hostname }}" + username: "{{ mt_user }}" + password: "{{ mt_pass }}" + state: "absent" + idempotent: "interface" + settings: + interface: "bridge3" + register: ip_addr_rem_3 + failed_when: ip_addr_rem_3 | changed + +- name: ALWAYS_CHANGES Add ip using idempotent interface on bridge4 + mt_ip_address: + hostname: "{{ mt_hostname }}" + username: "{{ mt_user }}" + password: "{{ mt_pass }}" + state: "present" + idempotent: "interface" + settings: + interface: "bridge4" + address: "192.168.89.4/24" + register: ip_addr_rem_4 + failed_when: not (ip_addr_rem_4 | changed) + +- name: ALWAYS_CHANGES Edit ip using idempotent interface on bridge4 + mt_ip_address: + hostname: "{{ mt_hostname }}" + username: "{{ mt_user }}" + password: "{{ mt_pass }}" + state: "present" + idempotent: "interface" + settings: + interface: "bridge4" + address: "192.168.89.5/24" + register: ip_addr_rem_4 + failed_when: not (ip_addr_rem_4 | changed) + +- name: ALWAYS_CHANGES Add comment using idempotent interface on bridge4 + mt_ip_address: + hostname: "{{ mt_hostname }}" + username: "{{ mt_user }}" + password: "{{ mt_pass }}" + state: "present" + idempotent: "interface" + settings: + interface: "bridge4" + comment: "This is a final comment" + register: ip_addr_rem_4 + failed_when: not (ip_addr_rem_4 | changed)