migrate bridge module into more generic interface one

This commit is contained in:
Valentin Gurmeza 2018-01-25 17:48:23 -08:00
parent 8392bf6f40
commit a28e8d27c4
4 changed files with 79 additions and 595 deletions

View file

@ -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()

View file

@ -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()

View file

@ -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,6 +86,13 @@ def main():
)
params = module.params
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(

View file

@ -1,22 +1,26 @@
---
- name: Add bridge1
mt_interface_bridge:
mt_interfaces:
hostname: "{{ mt_hostname }}"
username: "{{ mt_user }}"
password: "{{ mt_pass }}"
name: "{{ item }}"
state: present
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
parameter: bridge
settings:
name: "{{ item }}"
arp: proxy-arp
with_items:
- "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 }}"
parameter: "bridge port"
state: present
settings:
bridge: "{{ item[0] }}"
interface: "{{ item[1] }}"
state: present
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 }}"
parameter: "bridge port"
state: present
settings:
bridge: "{{ item[0] }}"
interface: "{{ item[1] }}"
state: present
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 }}"
parameter: "bridge port"
state: present
settings:
bridge: "{{ item[0] }}"
interface: "{{ item[1] }}"
edge: "{{ item[2] }}"
state: present
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 }}"
parameter: "bridge port"
state: present
settings:
bridge: bridge1
interface: ether7
state: present
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 }}"
parameter: "bridge port"
state: absent
settings:
bridge: bridge1
interface: ether7
state: absent
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 }}"
parameter: "bridge"
state: present
name: "{{ item.key }}"
arp: "{{ item.value.arp }}"
with_dict:
bridge2:
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