mirror of https://github.com/ansible/ansible.git
Removing alpha-stage modules.
parent
029786a4c5
commit
7f86da31b9
@ -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 New Issue