diff --git a/library/mt_interface_bridge.py b/library/mt_interface_bridge.py deleted file mode 100644 index db05e8d..0000000 --- a/library/mt_interface_bridge.py +++ /dev/null @@ -1,296 +0,0 @@ -# -*- coding: utf-8 -*- -DOCUMENTATION = ''' -module: mt_interface_bridge -author: - - "Valentin Gurmeza" - - "Shaun Smiley" -version_added: "2.3" -short_description: Manage mikrotik bridge -requirements: - - mt_api -description: - - add, remove, or modify a bridge. -options: - hostname: - description: - - hotstname of mikrotik router - required: True - username: - description: - - username used to connect to mikrotik router - required: True - password: - description: - - password used for authentication to mikrotik router - required: True - state: - description: - - bridge present or absent - required: True # if modifying bridge - choices: - - present - - absent - name: - description: - - name of the bridge - comment: - description: - - brige comment - admin_mac: - description: - - Static MAC address of the bridge (takes effect if auto-mac=no) - ageing_time: - description: - - How long a host's information will be kept in the bridge database - arp: - description: - - Address Resolution Protocol setting - choices: - - disabled - - enabled - - proxy-arp - - reply-only - auto_mac: - description: - - Automatically select one MAC address of bridge ports as a bridge MAC address - choices: - - yes - - no - forward_delay: - description: - - Time which is spent during the initialization phase of the bridge interface (i.e., after router startup or enabling the interface) in listening/learning state before the bridge will start functioning normally - max_message_age: - description: - - How long to remember Hello messages received from other bridges - mtu: - description: - - Maximum Transmission Unit - priority: - description: - - Spanning tree protocol priority for bridge interface - protocol_mode: - description: - - Select Spanning tree protocol (STP) or Rapid spanning tree protocol (RSTP) to ensure a loop-free topology for any bridged LAN - choices: - - none - - rstp - - stp - transmit_hold_count: - description: - - The Transmit Hold Count used by the Port Transmit state machine to limit transmission rate - settings: - description: - - Bridge settings. If defined this argument is a key/value dictionary - choices: - - allow-fast-path: yes/no - - use-ip-firewall: yes/no - - use-ip-firewall-for-ppoe: yes/no - - use-ip-firewall-for-bridge: yes/no - - -''' - -EXAMPLES = ''' -- mt_interface_bridge: - hostname: "{{ inventory_hostname }}" - username: "{{ mt_user }}" - password: "{{ mt_pass }}" - state: present - name: bridge_native - interface: ether7 - comment: ansible_test -''' - -from ansible.module_utils import mt_api -from ansible.module_utils.mt_common import clean_params -from ansible.module_utils.basic import AnsibleModule - - -def main(): - module = AnsibleModule( - argument_spec=dict( - hostname = dict(required=True), - username = dict(required=True), - password = dict(required=True, no_log=True), - name = dict(required=False, type='str'), - comment = dict(required=False, type='str'), - admin_mac = dict(required=False, type='str'), - auto_mac = dict(required=False, type='str'), - ageing_time = dict(required=False, type='str'), - forward_delay = dict(required=False, type='str'), - max_message_age=dict(required=False, type='str'), - transmit_hold_count=dict(required=False, type='str'), - arp = dict( - required = False, - choices = ['disabled', 'enabled', 'proxy-arp', 'reply-only'], - type='str' - ), - protocol_mode= dict( - required = False, - choices = ['none', 'rstp', 'stp'], - type='str' - ), - settings= dict( - required = False, - type='dict' - ), - state= dict( - required = False, - choices = ['present', 'absent'], - type = 'str' - ), - ), - supports_check_mode=True - ) - - hostname = module.params['hostname'] - username = module.params['username'] - password = module.params['password'] - state = module.params['state'] - ansible_bridge_name = module.params['name'] - check_mode = module.check_mode - changed = False - changed_message = [] - msg = "" - - mk = mt_api.Mikrotik(hostname, username, password) - try: - mk.login() - except: - module.fail_json( - msg="Could not log into Mikrotik device." + - " Check the username and password.", - ) - - bridge_path = '/interface/bridge' - - response = mk.api_print(base_path=bridge_path) - bridge_params = module.params - mikrotik_bridge = {} - for item in response: - if 'name' in item[1]: - if ansible_bridge_name == item[1]['name']: - mikrotik_bridge = item[1] - - ######################################################## - # Check if we need to edit the bridge settings - ######################################################## - if bridge_params['settings'] is not None: - settings_path = '/interface/bridge/settings' - settings_response = mk.api_print(settings_path) - settings_response = settings_response[0][1] - settings = bridge_params['settings'] - bridge_settings_diff_keys = {} - - for key in settings: - if isinstance(settings[key], bool): - settings[key] = str(settings[key]) - settings[key] = str.lower(settings[key]) - else: - if settings[key] == "yes": - settings[key] = "true" - if settings[key] == "no": - settings[key] = "false" - - for key in settings: - if key in settings_response: - if settings[key] != settings_response[key]: - bridge_settings_diff_keys[key] = settings[key] - else: - bridge_settings_diff_keys[key] = settings[key] - - if bridge_settings_diff_keys != {}: - if not check_mode: - mk.api_edit(base_path=settings_path, params=bridge_settings_diff_keys) - changed_message.append(bridge_settings_diff_keys) - changed = True - else: - changed = False - - ####################################### - # remove unneeded parameters - # clean up parameters - ###################################### - - remove_params = ['hostname', 'username', 'password', 'state', 'settings'] - for i in remove_params: - del bridge_params[i] - - clean_params(bridge_params) - - if '.id' in mikrotik_bridge: - client_id = mikrotik_bridge['.id'] - else: - client_id = False - - ################################################################## - # We need to make sure that bridge_bridge name is a string - # if it's null then it has not been defined. - ################################################################### - if (state == "present" and isinstance(ansible_bridge_name, str)): - if mikrotik_bridge == {}: - if not check_mode: - mk.api_add( - base_path=bridge_path, - params=bridge_params - ) - changed_message.append(ansible_bridge_name + " added") - changed = True, - else: - bridge_diff_keys = {} - - for key in bridge_params: - if key in mikrotik_bridge: - if bridge_params[key] != mikrotik_bridge[key]: - bridge_diff_keys[key] = bridge_params[key] - else: - bridge_diff_keys[key] = bridge_params[key] - if bridge_diff_keys != {}: - bridge_diff_keys['numbers'] = client_id - if not check_mode: - mk.api_edit(base_path=bridge_path, params=bridge_diff_keys) - changed = True - changed_message.append("Changed bridge: " + bridge_params['name']) - else: - #################### - # Already up date - ################### - if not changed: - changed = False - - elif state == "absent": - if client_id: - if not check_mode: - mk.api_remove(base_path=bridge_path, remove_id=client_id) - changed_message.append(bridge_params['name'] + " removed") - changed = True - ##################################################### - # if client_id is not set there is nothing to remove - ##################################################### - else: - if not changed: - changed = False - elif settings: - ######################################################## - # if settings were set we were modifying bridge settings - # only - pass - else: - module.exit_json( - failed=True, - changed=False, - ) - - if changed: - module.exit_json( - failed=False, - changed=True, - msg=changed_message - ) - else: - module.exit_json( - failed=False, - changed=False, - ) -if __name__ == '__main__': - main() diff --git a/library/mt_interface_bridge_port.py b/library/mt_interface_bridge_port.py deleted file mode 100644 index 77ec052..0000000 --- a/library/mt_interface_bridge_port.py +++ /dev/null @@ -1,247 +0,0 @@ -# -*- coding: utf-8 -*- -DOCUMENTATION = ''' -module: mt_interface_bridge_port -author: - - "Valentin Gurmeza" - - "Shaun Smiley" -version_added: "2.3" -short_description: Manage mikrotik bridge_port -requirements: - - mt_api -description: - - add, remove, or modify a bridge_port. -options: - hostname: - description: - - hotstname of mikrotik router - required: True - username: - description: - - username used to connect to mikrotik router - required: True - password: - description: - - password used for authentication to mikrotik router - required: True - state: - description: - - inteface present or absent in the bridge - required: True - choices: - - present - - absent - comment: - description: - - brige comment - auto_isolate: - description: - - Prevents STP blocking port from erroneously moving into a forwarding state if no BPDU's are received on the bridge - choices: - - yes - - no - bridge: - description: - - The bridge interface the respective interface is grouped in - edge: - description: - - Set port as edge port or non-edge port, or enable automatic detection. Edge ports are connected to a LAN that has no other bridge attached. If the port is configured to discover edge port then as soon as the bridge_ detects a BPDU coming to an edge port, the port becomes a non-edge port - choices: - - auto - - no - - no-discover - - yes - - yes-discover - external_fdb: - description: - - Whether to use wireless registration table to speed up bridge host learning - choices: - - yes - - no - - auto - horizon: - description: - - Use split horizon bridging to prevent bridging loops - interface: - description: - - Name of the interface - path_cost: - description: - - Path cost to the interface, used by STP to determine the "best" path - point_to_point: - description: - - point to point - choices: - - yes - - no - - auto - priority: - description: - - The priority of the interface in comparison with other going to the same subnet -''' - -EXAMPLES = ''' -- mt_interface_bridge_port: - hostname: "{{ inventory_hostname }}" - username: "{{ mt_user }}" - password: "{{ mt_pass }}" - state: present - name: bridge_port_native - interface: ether7 - comment: ansible_test -''' - -from ansible.module_utils import mt_api -from ansible.module_utils.mt_common import clean_params -from ansible.module_utils.basic import AnsibleModule - - -def main(): - module = AnsibleModule( - argument_spec=dict( - hostname =dict(required=True), - username =dict(required=True), - password =dict(required=True, no_log=True), - interface =dict(required=True, type='str'), - bridge =dict(required=False, type='str'), - comment =dict(required=False, type='str'), - path_cost =dict(required=False, type='str'), - priority =dict(required=False, type='str'), - horizon =dict(required=False, type='str'), - external_fdb=dict( - required=False, - choices=['yes', 'no', 'auto'], - type='str' - ), - auto_isolate=dict( - required=False, - choices=['yes', 'no'], - type='str' - ), - edge=dict( - required=False, - choices=['auto', 'yes', 'no', 'no-discover', 'yes-discover'], - type='str' - ), - point_to_point=dict( - required=False, - choices=['yes', 'no', 'auto'], - type='str' - ), - state=dict( - required=True, - choices=['present', 'absent'], - type='str' - ), - ), - supports_check_mode=True - ) - - hostname = module.params['hostname'] - username = module.params['username'] - password = module.params['password'] - state = module.params['state'] - ansible_bridge_port_interface = module.params['interface'] - changed = False - changed_message = [] - check_mode = module.check_mode - msg = "" - - mk = mt_api.Mikrotik(hostname, username, password) - try: - mk.login() - except: - module.fail_json( - msg="Could not log into Mikrotik device." + - " Check the username and password.", - ) - - bridge_port_path = '/interface/bridge/port' - - response = mk.api_print(base_path=bridge_port_path) - bridge_port_params = module.params - mikrotik_bridge_port = {} - for item in response: - if 'interface' in item[1].keys(): - if ansible_bridge_port_interface == item[1]['interface']: - mikrotik_bridge_port = item[1] - - ####################################### - # remove unneeded parameters - ###################################### - - remove_params = ['hostname', 'username', 'password', 'state'] - for i in remove_params: - del bridge_port_params[i] - - ########################################## - # modify clean_params in place - ############################################ - clean_params(bridge_port_params) - - if '.id' in mikrotik_bridge_port: - client_id = mikrotik_bridge_port['.id'] - else: - client_id = False - - if state == "present": - if mikrotik_bridge_port == {}: - if not check_mode: - mk.api_add( - base_path=bridge_port_path, - params=bridge_port_params - ) - changed_message.append(ansible_bridge_port_interface + " added to bridge") - changed = True, - else: - bridge_port_diff_keys = {} - - for key in bridge_port_params: - if key in mikrotik_bridge_port: - if bridge_port_params[key] != mikrotik_bridge_port[key]: - bridge_port_diff_keys[key] = bridge_port_params[key] - else: - bridge_port_diff_keys[key] = bridge_port_params[key] - if bridge_port_diff_keys != {}: - bridge_port_diff_keys['numbers'] = client_id - if not check_mode: - mk.api_edit(base_path=bridge_port_path, params=bridge_port_diff_keys) - changed = True - changed_message.append("Changed bridge port: " + bridge_port_params['bridge']) - else: - #################### - # Already up date - ################### - if not changed: - changed = False - - elif state == "absent": - if client_id: - if not check_mode: - mk.api_remove(base_path=bridge_port_path, remove_id=client_id) - changed_message.append(bridge_port_params['interface'] + " removed") - changed = True - ##################################################### - # if client_id is not set there is nothing to remove - ##################################################### - else: - if not changed: - changed = False - else: - module.exit_json( - failed=True, - changed=False, - ) - - if changed: - module.exit_json( - failed=False, - changed=True, - msg=changed_message - ) - else: - module.exit_json( - failed=False, - changed=False, - ) -if __name__ == '__main__': - main() diff --git a/library/mt_interfaces.py b/library/mt_interfaces.py index 4194855..bed732e 100644 --- a/library/mt_interfaces.py +++ b/library/mt_interfaces.py @@ -64,12 +64,19 @@ def main(): username=dict(required=True), password=dict(required=True, no_log=True), settings=dict(required=True, type='dict'), - parameter = dict( - required = True, - choices = ['ethernet', 'vlan', 'ovpn-client'], - type = 'str' + parameter=dict( + required=True, + choices=[ + 'ethernet', + 'vlan', + 'ovpn-client', + 'bridge', + 'bridge port', + 'bridge settings' + ], + type='str' ), - state = dict( + state=dict( required = False, choices = ['present', 'absent'], type = 'str' @@ -79,7 +86,14 @@ def main(): ) params = module.params - idempotent_parameter = 'name' + if params['parameter'] == 'bridge port': + params['parameter'] = 'bridge/port' + idempotent_parameter = "interface" + elif params['parameter'] == 'bridge settings': + params['parameter'] = 'bridge/settings' + idempotent_parameter = None + else: + idempotent_parameter = 'name' mt_obj = MikrotikIdempotent( hostname = params['hostname'], diff --git a/tests/integration/tasks/test-bridge.yml b/tests/integration/tasks/test-bridge.yml index adba61c..1b603ec 100644 --- a/tests/integration/tasks/test-bridge.yml +++ b/tests/integration/tasks/test-bridge.yml @@ -1,23 +1,27 @@ --- - name: Add bridge1 - mt_interface_bridge: + mt_interfaces: hostname: "{{ mt_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" - name: "{{ item }}" state: present - arp: proxy-arp + parameter: bridge + settings: + name: "{{ item }}" + arp: proxy-arp with_items: - "bridge1" - name: Add bridge1 again (idempotency test) - mt_interface_bridge: + mt_interfaces: hostname: "{{ mt_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" - name: "{{ item }}" state: present - arp: proxy-arp + parameter: bridge + settings: + name: "{{ item }}" + arp: proxy-arp with_items: - "bridge1" register: mod_bridge1 @@ -30,25 +34,29 @@ # bridge ports depend on bridge being created first - name: Add interface to bridge1 (port) - mt_interface_bridge_port: + mt_interfaces: hostname: "{{ mt_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" - bridge: "{{ item[0] }}" - interface: "{{ item[1] }}" + parameter: "bridge port" state: present + settings: + bridge: "{{ item[0] }}" + interface: "{{ item[1] }}" with_nested: - [ "bridge1" ] - [ "ether8" ] - name: Add interface to bridge1 (port) again (idempotency test) - mt_interface_bridge_port: + mt_interfaces: hostname: "{{ mt_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" - bridge: "{{ item[0] }}" - interface: "{{ item[1] }}" + parameter: "bridge port" state: present + settings: + bridge: "{{ item[0] }}" + interface: "{{ item[1] }}" with_nested: - [ "bridge1" ] - [ "ether8" ] @@ -60,27 +68,31 @@ ) - name: Add additional param to bridge port - mt_interface_bridge_port: + mt_interfaces: hostname: "{{ mt_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" - bridge: "{{ item[0] }}" - interface: "{{ item[1] }}" - edge: "{{ item[2] }}" + parameter: "bridge port" state: present + settings: + bridge: "{{ item[0] }}" + interface: "{{ item[1] }}" + edge: "{{ item[2] }}" with_nested: - [ "bridge1" ] - [ "ether8" ] - [ "yes-discover" ] - name: ALWAYS_CHANGES Add 2nd interface to bridge1 port - mt_interface_bridge_port: + mt_interfaces: hostname: "{{ mt_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" - bridge: bridge1 - interface: ether7 - state: present + parameter: "bridge port" + state: present + settings: + bridge: bridge1 + interface: ether7 with_nested: - [ "bridge1" ] - [ "ether7" ] @@ -92,13 +104,15 @@ ) - name: ALWAYS_CHANGES Remove 2nd interface to bridge1 port - mt_interface_bridge_port: + mt_interfaces: hostname: "{{ mt_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" - bridge: bridge1 - interface: ether7 + parameter: "bridge port" state: absent + settings: + bridge: bridge1 + interface: ether7 with_nested: - [ "bridge1" ] - [ "ether7" ] @@ -110,39 +124,38 @@ ) - name: Add bridge2 - mt_interface_bridge: + mt_interfaces: hostname: "{{ mt_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" - state: present - name: "{{ item.key }}" - arp: "{{ item.value.arp }}" - with_dict: - bridge2: - arp: "reply-only" - + parameter: "bridge" + state: present + settings: + name: "bridge2" + arp: "reply-only" - name: Adjust settings - mt_interface_bridge: + mt_interfaces: hostname: "{{ mt_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" - #state: present + parameter: "bridge settings" settings: - allow-fast-path: yes - use-ip-firewall-for-vlan: yes - use-ip-firewall-for-pppoe: no + allow-fast-path: "yes" + use-ip-firewall: "yes" + use-ip-firewall-for-vlan: "yes" + use-ip-firewall-for-pppoe: "no" - name: Adjust settings (test changes) - mt_interface_bridge: + mt_interfaces: hostname: "{{ mt_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" - #state: present + parameter: "bridge settings" settings: - allow-fast-path: yes - use-ip-firewall-for-vlan: no - use-ip-firewall-for-pppoe: no + allow-fast-path: "yes" + use-ip-firewall-for-vlan: "no" + use-ip-firewall-for-pppoe: "no" register: bridge_settings_1 failed_when: ( not ansible_check_mode @@ -151,15 +164,15 @@ ) - name: Adjust settings again (idempotency test) - mt_interface_bridge: + mt_interfaces: hostname: "{{ mt_hostname }}" username: "{{ mt_user }}" password: "{{ mt_pass }}" - #state: present + parameter: "bridge settings" settings: - allow-fast-path: yes - use-ip-firewall-for-vlan: no - use-ip-firewall-for-pppoe: no + allow-fast-path: "yes" + use-ip-firewall-for-vlan: "no" + use-ip-firewall-for-pppoe: "no" register: bridge_settings_2 failed_when: ( not ansible_check_mode