Removing alpha-stage modules.
This commit is contained in:
parent
029786a4c5
commit
7f86da31b9
3 changed files with 0 additions and 895 deletions
|
@ -1,214 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# (c) 2016, Cumulus Networks <ce-ceng@cumulusnetworks.com>
|
|
||||||
#
|
|
||||||
# This file is part of Ansible
|
|
||||||
# Ansible is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
# Ansible is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
---
|
|
||||||
module: cl_prefix_check
|
|
||||||
version_added: "2.1"
|
|
||||||
author: "Cumulus Networks (@CumulusNetworks)"
|
|
||||||
short_description: Check to see if route/prefix exists
|
|
||||||
description:
|
|
||||||
- Check to see if a route exists. This module can be used simply to check a
|
|
||||||
route and return if its present or absent. A larger timeout can be
|
|
||||||
provided to check if a route disappears. An example would be the user
|
|
||||||
could change the OSPF cost of a node within the network then utilize
|
|
||||||
cl_prefix_check of another (separate) node to verify the node (where the
|
|
||||||
OSPF cost was changed) is not being use to route traffic.
|
|
||||||
options:
|
|
||||||
prefix:
|
|
||||||
description:
|
|
||||||
- route/prefix that module is checking for. Uses format acceptable
|
|
||||||
to "ip route show" command. See manpage of "ip-route" for more
|
|
||||||
details
|
|
||||||
required: true
|
|
||||||
state:
|
|
||||||
description:
|
|
||||||
- Describes if the prefix should be present.
|
|
||||||
choices: ['present', 'absent']
|
|
||||||
default: ['present']
|
|
||||||
timeout:
|
|
||||||
description:
|
|
||||||
- timeout in seconds to wait for route condition to be met
|
|
||||||
default: 5
|
|
||||||
poll_interval:
|
|
||||||
description:
|
|
||||||
- poll interval in seconds to check route.
|
|
||||||
default: 1
|
|
||||||
nonexthop:
|
|
||||||
description:
|
|
||||||
- address of node is not desired in result to prefix
|
|
||||||
default: ""
|
|
||||||
nexthop:
|
|
||||||
description:
|
|
||||||
- address of node is desired in result to prefix
|
|
||||||
default: ""
|
|
||||||
|
|
||||||
notes:
|
|
||||||
- IP Route Documentation -
|
|
||||||
http://manpages.ubuntu.com/manpages/precise/man8/route.8.html
|
|
||||||
'''
|
|
||||||
EXAMPLES = '''
|
|
||||||
Example playbook entries using the cl_prefix_check module to check if a prefix
|
|
||||||
exists
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Test if prefix is present.
|
|
||||||
cl_prefix_check: prefix=4.4.4.0/24
|
|
||||||
|
|
||||||
- name: Test if route is absent. poll for 200 seconds. Poll interval at
|
|
||||||
default setting of 1 second
|
|
||||||
cl_prefix_check: prefix=10.0.1.0/24 timeout=200 state=absent
|
|
||||||
|
|
||||||
- name: Test if route is present, with a timeout of 10 seconds and poll
|
|
||||||
interval of 2 seconds
|
|
||||||
cl_prefix_check: prefix=10.1.1.0/24 timeout=10 poll_interval=2
|
|
||||||
|
|
||||||
- name: Test if route is present, with a nexthop of 4.4.4.4 will fail if no
|
|
||||||
nexthop of 5.5.5.5
|
|
||||||
cl_prefix_check: prefix=4.4.4.4 nexthop=5.5.5.5
|
|
||||||
|
|
||||||
- name: Test if route is present, with no nexthop of 3.3.3.3 will fail if
|
|
||||||
there is a nexthop of 6.6.6.6
|
|
||||||
cl_prefix_check: prefix=3.3.3.3 nonexthop=6.6.6.6
|
|
||||||
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
RETURN = '''
|
|
||||||
changed:
|
|
||||||
description: whether the interface was changed
|
|
||||||
returned: changed
|
|
||||||
type: bool
|
|
||||||
sample: True
|
|
||||||
msg:
|
|
||||||
description: human-readable report of success or failure
|
|
||||||
returned: always
|
|
||||||
type: string
|
|
||||||
sample: "interface bond0 config updated"
|
|
||||||
'''
|
|
||||||
|
|
||||||
def run_cl_cmd(module, cmd, check_rc=True):
|
|
||||||
try:
|
|
||||||
(rc, out, err) = module.run_command(cmd, check_rc=check_rc)
|
|
||||||
except Exception, e:
|
|
||||||
module.fail_json(msg=e.strerror)
|
|
||||||
# trim last line as it is always empty
|
|
||||||
ret = out.splitlines()
|
|
||||||
f = open('workfile', 'w')
|
|
||||||
for a in ret:
|
|
||||||
f.write(a)
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def route_is_present(result):
|
|
||||||
if len(result) > 0:
|
|
||||||
return True
|
|
||||||
|
|
||||||
def route_is_absent(result):
|
|
||||||
if len(result) == 0:
|
|
||||||
return True
|
|
||||||
|
|
||||||
def check_hop(result,hop):
|
|
||||||
for line in result:
|
|
||||||
if hop in line.split():
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def check_next_hops(module, result):
|
|
||||||
nexthop = module.params.get('nexthop')
|
|
||||||
nonexthop = module.params.get('nonexthop')
|
|
||||||
prefix = module.params.get('prefix')
|
|
||||||
|
|
||||||
if not nexthop and not nonexthop:
|
|
||||||
return True
|
|
||||||
elif not nexthop and nonexthop:
|
|
||||||
if check_hop(result,nonexthop)==False:
|
|
||||||
return True
|
|
||||||
elif nexthop and not nonexthop:
|
|
||||||
if check_hop(result,nexthop)==True:
|
|
||||||
return True
|
|
||||||
elif nexthop and nonexthop:
|
|
||||||
if check_hop(result,nexthop)==True and check_hop(result,nonexthop)==False:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return false
|
|
||||||
|
|
||||||
def loop_route_check(module):
|
|
||||||
prefix = module.params.get('prefix')
|
|
||||||
state = module.params.get('state')
|
|
||||||
timeout = int(module.params.get('timeout'))
|
|
||||||
poll_interval = int(module.params.get('poll_interval'))
|
|
||||||
|
|
||||||
# using ip route show instead of ip route get
|
|
||||||
# because ip route show will be blank if the exact prefix
|
|
||||||
# is missing from the table. ip route get tries longest prefix
|
|
||||||
# match so may match default route.
|
|
||||||
# command returns empty array if prefix is missing
|
|
||||||
cl_prefix_cmd = '/sbin/ip route show %s' % (prefix)
|
|
||||||
time_elapsed = 0
|
|
||||||
while True:
|
|
||||||
result = run_cl_cmd(module, cl_prefix_cmd)
|
|
||||||
if state == 'present' and route_is_present(result):
|
|
||||||
if check_next_hops(module, result)==True:
|
|
||||||
return True
|
|
||||||
if state == 'absent' and route_is_absent(result):
|
|
||||||
if check_next_hops(module, result)==True:
|
|
||||||
return True
|
|
||||||
time.sleep(poll_interval)
|
|
||||||
time_elapsed += poll_interval
|
|
||||||
if time_elapsed == timeout:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
module = AnsibleModule(
|
|
||||||
argument_spec=dict(
|
|
||||||
prefix=dict(required=True, type='str'),
|
|
||||||
state=dict(default='present', type='str',
|
|
||||||
choices=['present', 'absent']),
|
|
||||||
timeout=dict(default=2, type='int'),
|
|
||||||
poll_interval=dict(default=1, type='int'),
|
|
||||||
nexthop=dict(default='', type='str'),
|
|
||||||
nonexthop=dict(default='', type='str'),
|
|
||||||
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
_state = module.params.get('state')
|
|
||||||
_timeout = module.params.get('timeout')
|
|
||||||
_msg = "Testing whether route is %s. " % (_state)
|
|
||||||
_nexthop = module.params.get('nexthop')
|
|
||||||
_nonexthop = module.params.get('nonexthop')
|
|
||||||
|
|
||||||
#checking for bad parameters
|
|
||||||
if _nexthop == _nonexthop and _nexthop != '':
|
|
||||||
module.fail_json(msg='nexthop and nonexthop cannot be the same')
|
|
||||||
|
|
||||||
#the loop
|
|
||||||
if loop_route_check(module):
|
|
||||||
_msg += 'Condition Met'
|
|
||||||
module.exit_json(msg=_msg, changed=False)
|
|
||||||
else:
|
|
||||||
_msg += 'Condition not met %s second timer expired' % (_timeout)
|
|
||||||
module.fail_json(msg='paremeters not found')
|
|
||||||
|
|
||||||
# import module snippets
|
|
||||||
from ansible.module_utils.basic import *
|
|
||||||
import time
|
|
||||||
# from ansible.module_utils.urls import *
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
|
@ -1,469 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# (c) 2016, Cumulus Networks <ce-ceng@cumulusnetworks.com>
|
|
||||||
#
|
|
||||||
# This file is part of Ansible
|
|
||||||
# Ansible is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
# Ansible is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
---
|
|
||||||
module: cl_quagga_ospf
|
|
||||||
version_added: "2.1"
|
|
||||||
author: "Cumulus Networks (@CumulusNetworks)"
|
|
||||||
short_description: Configure basic OSPFv2 parameters and interfaces using Quagga
|
|
||||||
description:
|
|
||||||
- Configures basic OSPFv2 global parameters such as
|
|
||||||
router id and bandwidth cost, or OSPFv2 interface configuration like
|
|
||||||
point-to-point settings or enabling OSPFv2 on an interface. Configuration
|
|
||||||
is applied to single OSPFv2 instance. Multiple OSPFv2 instance
|
|
||||||
configuration is currently not supported. It requires Quagga version
|
|
||||||
0.99.22 and higher with the non-modal Quagga CLI developed by Cumulus
|
|
||||||
Linux. For more details go to the Routing User Guide at
|
|
||||||
http://docs.cumulusnetworks.com/ and Quagga Docs at
|
|
||||||
http://www.nongnu.org/quagga/
|
|
||||||
options:
|
|
||||||
router_id:
|
|
||||||
description:
|
|
||||||
- Set the OSPFv2 router id
|
|
||||||
required: true
|
|
||||||
reference_bandwidth:
|
|
||||||
description:
|
|
||||||
- Set the OSPFv2 auto cost reference bandwidth
|
|
||||||
default: 40000
|
|
||||||
saveconfig:
|
|
||||||
description:
|
|
||||||
- Boolean. Issue write memory to save the config
|
|
||||||
choices: ['yes', 'no']
|
|
||||||
default: ['no']
|
|
||||||
interface:
|
|
||||||
description:
|
|
||||||
- define the name the interface to apply OSPFv2 services.
|
|
||||||
point2point:
|
|
||||||
description:
|
|
||||||
- Boolean. enable OSPFv2 point2point on the interface
|
|
||||||
choices: ['yes', 'no']
|
|
||||||
require_together:
|
|
||||||
- with interface option
|
|
||||||
area:
|
|
||||||
description:
|
|
||||||
- defines the area the interface is in
|
|
||||||
required_together:
|
|
||||||
- with interface option
|
|
||||||
cost:
|
|
||||||
description:
|
|
||||||
- define ospf cost.
|
|
||||||
required_together:
|
|
||||||
- with interface option
|
|
||||||
passive:
|
|
||||||
description:
|
|
||||||
- make OSPFv2 interface passive
|
|
||||||
choices: ['yes', 'no']
|
|
||||||
required_together:
|
|
||||||
- with interface option
|
|
||||||
state:
|
|
||||||
description:
|
|
||||||
- Describes if OSPFv2 should be present on a particular interface.
|
|
||||||
Module currently does not check that interface is not associated
|
|
||||||
with a bond or bridge. User will have to manually clear the
|
|
||||||
configuration of the interface from the bond or bridge. This will
|
|
||||||
be implemented in a later release
|
|
||||||
choices: [ 'present', 'absent']
|
|
||||||
default: 'present'
|
|
||||||
required_together:
|
|
||||||
- with interface option
|
|
||||||
requirements: ['Cumulus Linux Quagga non-modal CLI, Quagga version 0.99.22 and higher']
|
|
||||||
'''
|
|
||||||
EXAMPLES = '''
|
|
||||||
Example playbook entries using the cl_quagga_ospf module
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: configure ospf router_id
|
|
||||||
cl_quagga_ospf: router_id=10.1.1.1
|
|
||||||
- name: enable OSPFv2 on swp1 and set it be a point2point OSPF
|
|
||||||
interface with a cost of 65535
|
|
||||||
cl_quagga_ospf: interface=swp1 point2point=yes cost=65535
|
|
||||||
- name: enable ospf on swp1-5
|
|
||||||
cl_quagga_ospf: interface={{ item }}
|
|
||||||
with_sequence: start=1 end=5 format=swp%d
|
|
||||||
- name: disable ospf on swp1
|
|
||||||
cl_quagga_ospf: interface=swp1 state=absent
|
|
||||||
'''
|
|
||||||
|
|
||||||
RETURN = '''
|
|
||||||
changed:
|
|
||||||
description: whether the interface was changed
|
|
||||||
returned: changed
|
|
||||||
type: bool
|
|
||||||
sample: True
|
|
||||||
msg:
|
|
||||||
description: human-readable report of success or failure
|
|
||||||
returned: always
|
|
||||||
type: string
|
|
||||||
sample: "interface bond0 config updated"
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
def run_cl_cmd(module, cmd, check_rc=True, split_lines=True):
|
|
||||||
try:
|
|
||||||
(rc, out, err) = module.run_command(cmd, check_rc=check_rc)
|
|
||||||
except Exception, e:
|
|
||||||
module.fail_json(msg=e.strerror)
|
|
||||||
# trim last line as it is always empty
|
|
||||||
if split_lines:
|
|
||||||
ret = out.splitlines()
|
|
||||||
else:
|
|
||||||
ret = out
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
def check_dsl_dependencies(module, input_options,
|
|
||||||
dependency, _depend_value):
|
|
||||||
for _param in input_options:
|
|
||||||
if module.params.get(_param):
|
|
||||||
if not module.params.get(dependency):
|
|
||||||
_param_output = module.params.get(_param)
|
|
||||||
_msg = "incorrect syntax. " + _param + " must have an interface option." + \
|
|
||||||
" Example 'cl_quagga_ospf: " + dependency + "=" + _depend_value + " " + \
|
|
||||||
_param + "=" + _param_output + "'"
|
|
||||||
module.fail_json(msg=_msg)
|
|
||||||
|
|
||||||
|
|
||||||
def has_interface_config(module):
|
|
||||||
if module.params.get('interface') is not None:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def get_running_config(module):
|
|
||||||
running_config = run_cl_cmd(module, '/usr/bin/vtysh -c "show run"')
|
|
||||||
got_global_config = False
|
|
||||||
got_interface_config = False
|
|
||||||
module.interface_config = {}
|
|
||||||
module.global_config = []
|
|
||||||
for line in running_config:
|
|
||||||
line = line.lower().strip()
|
|
||||||
# ignore the '!' lines or blank lines
|
|
||||||
if len(line.strip()) <= 1:
|
|
||||||
if got_global_config:
|
|
||||||
got_global_config = False
|
|
||||||
if got_interface_config:
|
|
||||||
got_interface_config = False
|
|
||||||
continue
|
|
||||||
# begin capturing global config
|
|
||||||
m0 = re.match('router\s+ospf', line)
|
|
||||||
if m0:
|
|
||||||
got_global_config = True
|
|
||||||
continue
|
|
||||||
m1 = re.match('^interface\s+(\w+)', line)
|
|
||||||
if m1:
|
|
||||||
module.ifacename = m1.group(1)
|
|
||||||
module.interface_config[module.ifacename] = []
|
|
||||||
got_interface_config = True
|
|
||||||
continue
|
|
||||||
if got_interface_config:
|
|
||||||
module.interface_config[module.ifacename].append(line)
|
|
||||||
continue
|
|
||||||
if got_global_config:
|
|
||||||
m3 = re.match('\s*passive-interface\s+(\w+)', line)
|
|
||||||
if m3:
|
|
||||||
ifaceconfig = module.interface_config.get(m3.group(1))
|
|
||||||
if ifaceconfig:
|
|
||||||
ifaceconfig.append('passive-interface')
|
|
||||||
else:
|
|
||||||
module.global_config.append(line)
|
|
||||||
continue
|
|
||||||
|
|
||||||
|
|
||||||
def get_config_line(module, stmt, ifacename=None):
|
|
||||||
if ifacename:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
for i in module.global_config:
|
|
||||||
if re.match(stmt, i):
|
|
||||||
return i
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def update_router_id(module):
|
|
||||||
router_id_stmt = 'ospf router-id '
|
|
||||||
actual_router_id_stmt = get_config_line(module, router_id_stmt)
|
|
||||||
router_id_stmt = 'ospf router-id ' + module.params.get('router_id')
|
|
||||||
if router_id_stmt != actual_router_id_stmt:
|
|
||||||
cmd_line = "/usr/bin/cl-ospf router-id set %s" %\
|
|
||||||
(module.params.get('router_id'))
|
|
||||||
run_cl_cmd(module, cmd_line)
|
|
||||||
module.exit_msg += 'router-id updated '
|
|
||||||
module.has_changed = True
|
|
||||||
|
|
||||||
|
|
||||||
def update_reference_bandwidth(module):
|
|
||||||
bandwidth_stmt = 'auto-cost reference-bandwidth'
|
|
||||||
actual_bandwidth_stmt = get_config_line(module, bandwidth_stmt)
|
|
||||||
bandwidth_stmt = bandwidth_stmt + ' ' + \
|
|
||||||
module.params.get('reference_bandwidth')
|
|
||||||
if bandwidth_stmt != actual_bandwidth_stmt:
|
|
||||||
cmd_line = "/usr/bin/cl-ospf auto-cost set reference-bandwidth %s" %\
|
|
||||||
(module.params.get('reference_bandwidth'))
|
|
||||||
run_cl_cmd(module, cmd_line)
|
|
||||||
module.exit_msg += 'reference bandwidth updated '
|
|
||||||
module.has_changed = True
|
|
||||||
|
|
||||||
|
|
||||||
def add_global_ospf_config(module):
|
|
||||||
module.has_changed = False
|
|
||||||
get_running_config(module)
|
|
||||||
if module.params.get('router_id'):
|
|
||||||
update_router_id(module)
|
|
||||||
if module.params.get('reference_bandwidth'):
|
|
||||||
update_reference_bandwidth(module)
|
|
||||||
if module.has_changed is False:
|
|
||||||
module.exit_msg = 'No change in OSPFv2 global config'
|
|
||||||
module.exit_json(msg=module.exit_msg, changed=module.has_changed)
|
|
||||||
|
|
||||||
|
|
||||||
def check_ip_addr_show(module):
|
|
||||||
cmd_line = "/sbin/ip addr show %s" % (module.params.get('interface'))
|
|
||||||
result = run_cl_cmd(module, cmd_line)
|
|
||||||
for _line in result:
|
|
||||||
m0 = re.match('\s+inet\s+\w+', _line)
|
|
||||||
if m0:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def get_interface_addr_config(module):
|
|
||||||
ifacename = module.params.get('interface')
|
|
||||||
cmd_line = "/sbin/ifquery --format json %s" % (ifacename)
|
|
||||||
int_config = run_cl_cmd(module, cmd_line, True, False)
|
|
||||||
ifquery_obj = json.loads(int_config)[0]
|
|
||||||
iface_has_address = False
|
|
||||||
if 'address' in ifquery_obj.get('config'):
|
|
||||||
for addr in ifquery_obj.get('config').get('address'):
|
|
||||||
try:
|
|
||||||
socket.inet_aton(addr.split('/')[0])
|
|
||||||
iface_has_address = True
|
|
||||||
break
|
|
||||||
except socket.error:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
iface_has_address = check_ip_addr_show(module)
|
|
||||||
if iface_has_address is False:
|
|
||||||
_msg = "interface %s does not have an IP configured. " +\
|
|
||||||
"Required for OSPFv2 to work"
|
|
||||||
module.fail_json(msg=_msg)
|
|
||||||
# for test purposes only
|
|
||||||
return iface_has_address
|
|
||||||
|
|
||||||
|
|
||||||
def enable_or_disable_ospf_on_int(module):
|
|
||||||
ifacename = module.params.get('interface')
|
|
||||||
_state = module.params.get('state')
|
|
||||||
iface_config = module.interface_config.get(ifacename)
|
|
||||||
if iface_config is None:
|
|
||||||
_msg = "%s is not found in Quagga config. " % (ifacename) + \
|
|
||||||
"Check that %s is active in kernel" % (ifacename)
|
|
||||||
module.fail_json(msg=_msg)
|
|
||||||
return False # for test purposes
|
|
||||||
found_area = None
|
|
||||||
for i in iface_config:
|
|
||||||
m0 = re.search('ip\s+ospf\s+area\s+([0-9.]+)', i)
|
|
||||||
if m0:
|
|
||||||
found_area = m0.group(1)
|
|
||||||
break
|
|
||||||
if _state == 'absent':
|
|
||||||
for i in iface_config:
|
|
||||||
if found_area:
|
|
||||||
cmd_line = '/usr/bin/cl-ospf clear %s area' % \
|
|
||||||
(ifacename)
|
|
||||||
run_cl_cmd(module, cmd_line)
|
|
||||||
module.has_changed = True
|
|
||||||
module.exit_msg += "OSPFv2 now disabled on %s " % (ifacename)
|
|
||||||
return False
|
|
||||||
area_id = module.params.get('area')
|
|
||||||
if found_area != area_id:
|
|
||||||
cmd_line = '/usr/bin/cl-ospf interface set %s area %s' % \
|
|
||||||
(ifacename, area_id)
|
|
||||||
run_cl_cmd(module, cmd_line)
|
|
||||||
module.has_changed = True
|
|
||||||
module.exit_msg += "OSPFv2 now enabled on %s area %s " % \
|
|
||||||
(ifacename, area_id)
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def update_point2point(module):
|
|
||||||
ifacename = module.params.get('interface')
|
|
||||||
point2point = module.params.get('point2point')
|
|
||||||
iface_config = module.interface_config.get(ifacename)
|
|
||||||
found_point2point = None
|
|
||||||
for i in iface_config:
|
|
||||||
m0 = re.search('ip\s+ospf\s+network\s+point-to-point', i)
|
|
||||||
if m0:
|
|
||||||
found_point2point = True
|
|
||||||
break
|
|
||||||
if point2point:
|
|
||||||
if not found_point2point:
|
|
||||||
cmd_line = '/usr/bin/cl-ospf interface set %s network point-to-point' % \
|
|
||||||
(ifacename)
|
|
||||||
run_cl_cmd(module, cmd_line)
|
|
||||||
module.has_changed = True
|
|
||||||
module.exit_msg += 'OSPFv2 point2point set on %s ' % (ifacename)
|
|
||||||
else:
|
|
||||||
if found_point2point:
|
|
||||||
cmd_line = '/usr/bin/cl-ospf interface clear %s network' % \
|
|
||||||
(ifacename)
|
|
||||||
run_cl_cmd(module, cmd_line)
|
|
||||||
module.has_changed = True
|
|
||||||
module.exit_msg += 'OSPFv2 point2point removed on %s ' % \
|
|
||||||
(ifacename)
|
|
||||||
|
|
||||||
|
|
||||||
def update_passive(module):
|
|
||||||
ifacename = module.params.get('interface')
|
|
||||||
passive = module.params.get('passive')
|
|
||||||
iface_config = module.interface_config.get(ifacename)
|
|
||||||
found_passive = None
|
|
||||||
for i in iface_config:
|
|
||||||
m0 = re.search('passive-interface', i)
|
|
||||||
if m0:
|
|
||||||
found_passive = True
|
|
||||||
break
|
|
||||||
if passive:
|
|
||||||
if not found_passive:
|
|
||||||
cmd_line = '/usr/bin/cl-ospf interface set %s passive' % \
|
|
||||||
(ifacename)
|
|
||||||
run_cl_cmd(module, cmd_line)
|
|
||||||
module.has_changed = True
|
|
||||||
module.exit_msg += '%s is now OSPFv2 passive ' % (ifacename)
|
|
||||||
else:
|
|
||||||
if found_passive:
|
|
||||||
cmd_line = '/usr/bin/cl-ospf interface clear %s passive' % \
|
|
||||||
(ifacename)
|
|
||||||
run_cl_cmd(module, cmd_line)
|
|
||||||
module.has_changed = True
|
|
||||||
module.exit_msg += '%s is no longer OSPFv2 passive ' % \
|
|
||||||
(ifacename)
|
|
||||||
|
|
||||||
|
|
||||||
def update_cost(module):
|
|
||||||
ifacename = module.params.get('interface')
|
|
||||||
cost = module.params.get('cost')
|
|
||||||
iface_config = module.interface_config.get(ifacename)
|
|
||||||
found_cost = None
|
|
||||||
for i in iface_config:
|
|
||||||
m0 = re.search('ip\s+ospf\s+cost\s+(\d+)', i)
|
|
||||||
if m0:
|
|
||||||
found_cost = m0.group(1)
|
|
||||||
break
|
|
||||||
|
|
||||||
if cost != found_cost and cost is not None:
|
|
||||||
cmd_line = '/usr/bin/cl-ospf interface set %s cost %s' % \
|
|
||||||
(ifacename, cost)
|
|
||||||
run_cl_cmd(module, cmd_line)
|
|
||||||
module.has_changed = True
|
|
||||||
module.exit_msg += 'OSPFv2 cost on %s changed to %s ' % \
|
|
||||||
(ifacename, cost)
|
|
||||||
elif cost is None and found_cost is not None:
|
|
||||||
cmd_line = '/usr/bin/cl-ospf interface clear %s cost' % \
|
|
||||||
(ifacename)
|
|
||||||
run_cl_cmd(module, cmd_line)
|
|
||||||
module.has_changed = True
|
|
||||||
module.exit_msg += 'OSPFv2 cost on %s changed to default ' % \
|
|
||||||
(ifacename)
|
|
||||||
|
|
||||||
|
|
||||||
def config_ospf_interface_config(module):
|
|
||||||
enable_int_defaults(module)
|
|
||||||
module.has_changed = False
|
|
||||||
# get all ospf related config from quagga both globally and iface based
|
|
||||||
get_running_config(module)
|
|
||||||
# if interface does not have ipv4 address module should fail
|
|
||||||
get_interface_addr_config(module)
|
|
||||||
# if ospf should be enabled, continue to check for the remaining attrs
|
|
||||||
if enable_or_disable_ospf_on_int(module):
|
|
||||||
# update ospf point-to-point setting if needed
|
|
||||||
update_point2point(module)
|
|
||||||
# update ospf interface cost if needed
|
|
||||||
update_cost(module)
|
|
||||||
# update ospf interface passive setting
|
|
||||||
update_passive(module)
|
|
||||||
|
|
||||||
|
|
||||||
def saveconfig(module):
|
|
||||||
if module.params.get('saveconfig') is True and\
|
|
||||||
module.has_changed:
|
|
||||||
run_cl_cmd(module, '/usr/bin/vtysh -c "wr mem"')
|
|
||||||
module.exit_msg += 'Saving Config '
|
|
||||||
|
|
||||||
|
|
||||||
def enable_int_defaults(module):
|
|
||||||
if not module.params.get('area'):
|
|
||||||
module.params['area'] = '0.0.0.0'
|
|
||||||
if not module.params.get('state'):
|
|
||||||
module.params['state'] = 'present'
|
|
||||||
|
|
||||||
|
|
||||||
def check_if_ospf_is_running(module):
|
|
||||||
if not os.path.exists('/var/run/quagga/ospfd.pid'):
|
|
||||||
_msg = 'OSPFv2 process is not running. Unable to execute command'
|
|
||||||
module.fail_json(msg=_msg)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
module = AnsibleModule(
|
|
||||||
argument_spec=dict(
|
|
||||||
reference_bandwidth=dict(type='str',
|
|
||||||
default='40000'),
|
|
||||||
router_id=dict(type='str'),
|
|
||||||
interface=dict(type='str'),
|
|
||||||
cost=dict(type='str'),
|
|
||||||
area=dict(type='str'),
|
|
||||||
state=dict(type='str',
|
|
||||||
choices=['present', 'absent']),
|
|
||||||
point2point=dict(type='bool', choices=BOOLEANS),
|
|
||||||
saveconfig=dict(type='bool', choices=BOOLEANS, default=False),
|
|
||||||
passive=dict(type='bool', choices=BOOLEANS)
|
|
||||||
),
|
|
||||||
mutually_exclusive=[['reference_bandwidth', 'interface'],
|
|
||||||
['router_id', 'interface']]
|
|
||||||
)
|
|
||||||
check_if_ospf_is_running(module)
|
|
||||||
|
|
||||||
check_dsl_dependencies(module, ['cost', 'state', 'area',
|
|
||||||
'point2point', 'passive'],
|
|
||||||
'interface', 'swp1')
|
|
||||||
module.has_changed = False
|
|
||||||
module.exit_msg = ''
|
|
||||||
if has_interface_config(module):
|
|
||||||
config_ospf_interface_config(module)
|
|
||||||
else:
|
|
||||||
# Set area to none before applying global config
|
|
||||||
module.params['area'] = None
|
|
||||||
add_global_ospf_config(module)
|
|
||||||
saveconfig(module)
|
|
||||||
if module.has_changed:
|
|
||||||
module.exit_json(msg=module.exit_msg, changed=module.has_changed)
|
|
||||||
else:
|
|
||||||
module.exit_json(msg='no change', changed=False)
|
|
||||||
|
|
||||||
# import module snippets
|
|
||||||
from ansible.module_utils.basic import *
|
|
||||||
import re
|
|
||||||
import os
|
|
||||||
import socket
|
|
||||||
# incompatible with ansible 1.4.4 - ubuntu 12.04 version
|
|
||||||
# from ansible.module_utils.urls import *
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
|
@ -1,212 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# (c) 2016, Cumulus Networks <ce-ceng@cumulusnetworks.com>
|
|
||||||
#
|
|
||||||
# This file is part of Ansible
|
|
||||||
# Ansible is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
# Ansible is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
---
|
|
||||||
module: cl_quagga_protocol
|
|
||||||
version_added: "2.1"
|
|
||||||
author: "Cumulus Networks (@CumulusNetworks)"
|
|
||||||
short_description: Enable routing protocol services via Quagga
|
|
||||||
description:
|
|
||||||
- Enable Quagga services available on Cumulus Linux. This includes OSPF
|
|
||||||
v2/v3 and BGP. Quagga services are defined in the /etc/quagga/daemons
|
|
||||||
file. This module creates a file that will only enable OSPF or BGP routing
|
|
||||||
protocols, because this is what Cumulus Linux currently supports. Zebra is
|
|
||||||
automatically enabled when a supported routing protocol is listed. If all
|
|
||||||
routing protocols are disabled, this module will disable zebra as well.
|
|
||||||
Using Ansible Templates you can run any supported or unsupported quagga
|
|
||||||
routing protocol. For more details go to the Quagga Documentation located
|
|
||||||
at http://docs.cumulusnetworks.com/ and at
|
|
||||||
http://www.nongnu.org/quagga/docs.html
|
|
||||||
options:
|
|
||||||
name:
|
|
||||||
description:
|
|
||||||
- name of the protocol to update
|
|
||||||
choices: ['ospfd', 'ospf6d', 'bgpd']
|
|
||||||
required: true
|
|
||||||
state:
|
|
||||||
description:
|
|
||||||
- describe whether the protocol should be enabled or disabled
|
|
||||||
choices: ['present', 'absent']
|
|
||||||
required: true
|
|
||||||
activate:
|
|
||||||
description:
|
|
||||||
- restart quagga process to activate the change. If the service
|
|
||||||
is already configured but not activated, setting activate=yes will
|
|
||||||
not activate the service. This will be fixed in an upcoming
|
|
||||||
release
|
|
||||||
choices: ['yes', 'no']
|
|
||||||
default: ['no']
|
|
||||||
requirements: ['Quagga version 0.99.23 and higher']
|
|
||||||
'''
|
|
||||||
EXAMPLES = '''
|
|
||||||
Example playbook entries using the cl_quagga module
|
|
||||||
|
|
||||||
## Enable OSPFv2. Do not activate the change
|
|
||||||
cl_quagga_protocol name="ospfd" state=present
|
|
||||||
|
|
||||||
## Disable OSPFv2. Do not activate the change
|
|
||||||
cl_quagga_protocol name="ospf6d" state=absent
|
|
||||||
|
|
||||||
## Enable BGPv2. Do not activate the change. Activating the change requires a
|
|
||||||
## restart of the entire quagga process.
|
|
||||||
cl_quagga_protocol name="bgpd" state=present
|
|
||||||
|
|
||||||
## Enable OSPFv2 and activate the change as this might not start quagga when you
|
|
||||||
## want it to
|
|
||||||
cl_quagga_protocol name="ospfd" state=present activate=yes
|
|
||||||
|
|
||||||
## To activate a configured service
|
|
||||||
|
|
||||||
- name: disable ospfv2 service. Its configured but not enabled
|
|
||||||
cl_quagga_protocol name=ospfd state=absent
|
|
||||||
|
|
||||||
- name: enable ospfv2 service and activate it
|
|
||||||
cl_quagga_protocol name=ospfd state=present activate=yes
|
|
||||||
'''
|
|
||||||
|
|
||||||
RETURN = '''
|
|
||||||
changed:
|
|
||||||
description: whether the interface was changed
|
|
||||||
returned: changed
|
|
||||||
type: bool
|
|
||||||
sample: True
|
|
||||||
msg:
|
|
||||||
description: human-readable report of success or failure
|
|
||||||
returned: always
|
|
||||||
type: string
|
|
||||||
sample: "interface bond0 config updated"
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
def run_cl_cmd(module, cmd, check_rc=True):
|
|
||||||
try:
|
|
||||||
(rc, out, err) = module.run_command(cmd, check_rc=check_rc)
|
|
||||||
except Exception, e:
|
|
||||||
module.fail_json(msg=e.strerror)
|
|
||||||
# trim last line as it is always empty
|
|
||||||
ret = out.splitlines()
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
def convert_to_yes_or_no(_state):
|
|
||||||
if _state == 'present':
|
|
||||||
_str = 'yes'
|
|
||||||
else:
|
|
||||||
_str = 'no'
|
|
||||||
return _str
|
|
||||||
|
|
||||||
|
|
||||||
def read_daemon_file(module):
|
|
||||||
f = open(module.quagga_daemon_file)
|
|
||||||
if f:
|
|
||||||
return f.readlines()
|
|
||||||
else:
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
|
||||||
def setting_is_configured(module):
|
|
||||||
_protocol = module.params.get('name')
|
|
||||||
_state = module.params.get('state')
|
|
||||||
_state = convert_to_yes_or_no(_state)
|
|
||||||
_daemon_output = read_daemon_file(module)
|
|
||||||
_str = "(%s)=(%s)" % (_protocol, 'yes|no')
|
|
||||||
_daemonstr = re.compile("\w+=yes")
|
|
||||||
_zebrastr = re.compile("zebra=(yes|no)")
|
|
||||||
_matchstr = re.compile(_str)
|
|
||||||
daemoncount = 0
|
|
||||||
module.disable_zebra = False
|
|
||||||
for _line in _daemon_output:
|
|
||||||
_match = re.match(_matchstr, _line)
|
|
||||||
_active_daemon_match = re.match(_daemonstr, _line)
|
|
||||||
_zebramatch = re.match(_zebrastr, _line)
|
|
||||||
if _active_daemon_match:
|
|
||||||
daemoncount += 1
|
|
||||||
if _zebramatch:
|
|
||||||
if _zebramatch.group(1) == 'no' and _state == 'yes':
|
|
||||||
return False
|
|
||||||
elif _match:
|
|
||||||
if _state == _match.group(2):
|
|
||||||
_msg = "%s is configured and is %s" % \
|
|
||||||
(_protocol, module.params.get('state'))
|
|
||||||
module.exit_json(msg=_msg, changed=False)
|
|
||||||
# for nosetests purposes only
|
|
||||||
if daemoncount < 3 and _state == 'no':
|
|
||||||
module.disable_zebra = True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def modify_config(module):
|
|
||||||
_protocol = module.params.get('name')
|
|
||||||
_state = module.params.get('state')
|
|
||||||
_state = convert_to_yes_or_no(_state)
|
|
||||||
_daemon_output = read_daemon_file(module)
|
|
||||||
_str = "(%s)=(%s)" % (_protocol, 'yes|no')
|
|
||||||
_zebrastr = re.compile("zebra=(yes|no)")
|
|
||||||
_matchstr = re.compile(_str)
|
|
||||||
write_to_file = open(module.quagga_daemon_file, 'w')
|
|
||||||
for _line in _daemon_output:
|
|
||||||
_match = re.match(_matchstr, _line)
|
|
||||||
_zebramatch = re.match(_zebrastr, _line)
|
|
||||||
if _zebramatch:
|
|
||||||
if module.disable_zebra is True and _state == 'no':
|
|
||||||
write_to_file.write('zebra=no\n')
|
|
||||||
elif _state == 'yes':
|
|
||||||
write_to_file.write('zebra=yes\n')
|
|
||||||
else:
|
|
||||||
write_to_file.write(_line)
|
|
||||||
elif _match:
|
|
||||||
if _state != _match.group(2):
|
|
||||||
_str = "%s=%s\n" % (_protocol, _state)
|
|
||||||
write_to_file.write(_str)
|
|
||||||
else:
|
|
||||||
write_to_file.write(_line)
|
|
||||||
write_to_file.close()
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
module = AnsibleModule(
|
|
||||||
argument_spec=dict(
|
|
||||||
name=dict(type='str',
|
|
||||||
choices=['ospfd', 'ospf6d', 'bgpd'],
|
|
||||||
required=True),
|
|
||||||
state=dict(type='str',
|
|
||||||
choices=['present', 'absent'],
|
|
||||||
required=True),
|
|
||||||
activate=dict(type='bool', choices=BOOLEANS, default=False)
|
|
||||||
))
|
|
||||||
module.quagga_daemon_file = '/etc/quagga/daemons'
|
|
||||||
setting_is_configured(module)
|
|
||||||
modify_config(module)
|
|
||||||
_protocol = module.params.get('name')
|
|
||||||
_state = module.params.get('state')
|
|
||||||
_state = convert_to_yes_or_no(_state)
|
|
||||||
_msg = "%s protocol setting modified to %s" % \
|
|
||||||
(_protocol, _state)
|
|
||||||
if module.params.get('activate') is True:
|
|
||||||
run_cl_cmd(module, '/usr/sbin/service quagga restart')
|
|
||||||
_msg += '. Restarted Quagga Service'
|
|
||||||
module.exit_json(msg=_msg, changed=True)
|
|
||||||
|
|
||||||
# import module snippets
|
|
||||||
from ansible.module_utils.basic import *
|
|
||||||
# incompatible with ansible 1.4.4 - ubuntu 12.04 version
|
|
||||||
# from ansible.module_utils.urls import *
|
|
||||||
import re
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
Loading…
Reference in a new issue