263 lines
7.9 KiB
Python
263 lines
7.9 KiB
Python
#!/usr/bin/python
|
|
# coding: utf-8 -*-
|
|
|
|
# (c) 2013, David Stygstra <david.stygstra@gmail.com>
|
|
# Portions copyright @ 2015 VMware, Inc.
|
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
|
|
from __future__ import absolute_import, division, print_function
|
|
__metaclass__ = type
|
|
|
|
|
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
'status': ['preview'],
|
|
'supported_by': 'network'}
|
|
|
|
|
|
DOCUMENTATION = '''
|
|
---
|
|
module: openvswitch_port
|
|
version_added: 1.4
|
|
author: "David Stygstra (@stygstra)"
|
|
short_description: Manage Open vSwitch ports
|
|
requirements: [ ovs-vsctl ]
|
|
description:
|
|
- Manage Open vSwitch ports
|
|
options:
|
|
bridge:
|
|
required: true
|
|
description:
|
|
- Name of bridge to manage
|
|
port:
|
|
required: true
|
|
description:
|
|
- Name of port to manage on the bridge
|
|
tag:
|
|
version_added: 2.2
|
|
description:
|
|
- VLAN tag for this port. Must be a value between
|
|
0 and 4095.
|
|
state:
|
|
default: "present"
|
|
choices: [ present, absent ]
|
|
description:
|
|
- Whether the port should exist
|
|
timeout:
|
|
default: 5
|
|
description:
|
|
- How long to wait for ovs-vswitchd to respond
|
|
external_ids:
|
|
version_added: 2.0
|
|
default: {}
|
|
description:
|
|
- Dictionary of external_ids applied to a port.
|
|
set:
|
|
version_added: 2.0
|
|
description:
|
|
- Set a single property on a port.
|
|
'''
|
|
|
|
EXAMPLES = '''
|
|
# Creates port eth2 on bridge br-ex
|
|
- openvswitch_port:
|
|
bridge: br-ex
|
|
port: eth2
|
|
state: present
|
|
|
|
# Creates port eth6
|
|
- openvswitch_port:
|
|
bridge: bridge-loop
|
|
port: eth6
|
|
state: present
|
|
set: Interface eth6
|
|
|
|
# Creates port vlan10 with tag 10 on bridge br-ex
|
|
- openvswitch_port:
|
|
bridge: br-ex
|
|
port: vlan10
|
|
tag: 10
|
|
state: present
|
|
set: Interface vlan10
|
|
|
|
# Assign interface id server1-vifeth6 and mac address 00:00:5E:00:53:23
|
|
# to port vifeth6 and setup port to be managed by a controller.
|
|
- openvswitch_port:
|
|
bridge: br-int
|
|
port: vifeth6
|
|
state: present
|
|
args:
|
|
external_ids:
|
|
iface-id: '{{ inventory_hostname }}-vifeth6'
|
|
attached-mac: '00:00:5E:00:53:23'
|
|
vm-id: '{{ inventory_hostname }}'
|
|
iface-status: active
|
|
'''
|
|
|
|
from ansible.module_utils.basic import AnsibleModule
|
|
from ansible.module_utils.six import iteritems
|
|
|
|
|
|
def _external_ids_to_dict(text):
|
|
text = text.strip()
|
|
|
|
if text == '{}':
|
|
return None
|
|
else:
|
|
d = {}
|
|
|
|
for kv in text[1:-1].split(','):
|
|
kv = kv.strip()
|
|
k, v = kv.split('=')
|
|
d[k] = v
|
|
|
|
return d
|
|
|
|
|
|
def _tag_to_str(text):
|
|
text = text.strip()
|
|
|
|
if text == '[]':
|
|
return None
|
|
else:
|
|
return text
|
|
|
|
|
|
def map_obj_to_commands(want, have, module):
|
|
commands = list()
|
|
|
|
if module.params['state'] == 'absent':
|
|
if have:
|
|
templatized_command = ("%(ovs-vsctl)s -t %(timeout)s del-port"
|
|
" %(bridge)s %(port)s")
|
|
command = templatized_command % module.params
|
|
commands.append(command)
|
|
else:
|
|
if have:
|
|
if want['tag'] != have['tag']:
|
|
templatized_command = ("%(ovs-vsctl)s -t %(timeout)s"
|
|
" set port %(port)s tag=%(tag)s")
|
|
command = templatized_command % module.params
|
|
commands.append(command)
|
|
|
|
if want['external_ids'] != have['external_ids']:
|
|
for k, v in iteritems(want['external_ids']):
|
|
if (not have['external_ids']
|
|
or k not in have['external_ids']
|
|
or want['external_ids'][k] != have['external_ids'][k]):
|
|
if v is None:
|
|
templatized_command = ("%(ovs-vsctl)s -t %(timeout)s"
|
|
" remove port %(port)s"
|
|
" external_ids " + k)
|
|
command = templatized_command % module.params
|
|
commands.append(command)
|
|
else:
|
|
templatized_command = ("%(ovs-vsctl)s -t %(timeout)s"
|
|
" set port %(port)s"
|
|
" external_ids:")
|
|
command = templatized_command % module.params
|
|
command += k + "=" + v
|
|
commands.append(command)
|
|
else:
|
|
templatized_command = ("%(ovs-vsctl)s -t %(timeout)s add-port"
|
|
" %(bridge)s %(port)s")
|
|
command = templatized_command % module.params
|
|
|
|
if want['tag']:
|
|
templatized_command = " tag=%(tag)s"
|
|
command += templatized_command % module.params
|
|
|
|
if want['set']:
|
|
templatized_command = " -- set %(set)s"
|
|
command += templatized_command % module.params
|
|
|
|
commands.append(command)
|
|
|
|
if want['external_ids']:
|
|
for k, v in iteritems(want['external_ids']):
|
|
templatized_command = ("%(ovs-vsctl)s -t %(timeout)s"
|
|
" set port %(port)s external_ids:")
|
|
command = templatized_command % module.params
|
|
command += k + "=" + v
|
|
commands.append(command)
|
|
|
|
return commands
|
|
|
|
|
|
def map_config_to_obj(module):
|
|
templatized_command = "%(ovs-vsctl)s -t %(timeout)s list-ports %(bridge)s"
|
|
command = templatized_command % module.params
|
|
rc, out, err = module.run_command(command, check_rc=True)
|
|
if rc != 0:
|
|
module.fail_json(msg=err)
|
|
|
|
obj = {}
|
|
|
|
if module.params['port'] in out.splitlines():
|
|
obj['bridge'] = module.params['bridge']
|
|
obj['port'] = module.params['port']
|
|
|
|
templatized_command = ("%(ovs-vsctl)s -t %(timeout)s get"
|
|
" Port %(port)s tag")
|
|
command = templatized_command % module.params
|
|
rc, out, err = module.run_command(command, check_rc=True)
|
|
obj['tag'] = _tag_to_str(out)
|
|
|
|
templatized_command = ("%(ovs-vsctl)s -t %(timeout)s get"
|
|
" Port %(port)s external_ids")
|
|
command = templatized_command % module.params
|
|
rc, out, err = module.run_command(command, check_rc=True)
|
|
obj['external_ids'] = _external_ids_to_dict(out)
|
|
|
|
return obj
|
|
|
|
|
|
def map_params_to_obj(module):
|
|
obj = {
|
|
'bridge': module.params['bridge'],
|
|
'port': module.params['port'],
|
|
'tag': module.params['tag'],
|
|
'external_ids': module.params['external_ids'],
|
|
'set': module.params['set']
|
|
}
|
|
|
|
return obj
|
|
|
|
|
|
def main():
|
|
""" Entry point. """
|
|
argument_spec = {
|
|
'bridge': {'required': True},
|
|
'port': {'required': True},
|
|
'state': {'default': 'present', 'choices': ['present', 'absent']},
|
|
'timeout': {'default': 5, 'type': 'int'},
|
|
'external_ids': {'default': None, 'type': 'dict'},
|
|
'tag': {'default': None},
|
|
'set': {'required': False, 'default': None}
|
|
}
|
|
|
|
module = AnsibleModule(argument_spec=argument_spec,
|
|
supports_check_mode=True)
|
|
|
|
result = {'changed': False}
|
|
|
|
# We add ovs-vsctl to module_params to later build up templatized commands
|
|
module.params["ovs-vsctl"] = module.get_bin_path("ovs-vsctl", True)
|
|
|
|
want = map_params_to_obj(module)
|
|
have = map_config_to_obj(module)
|
|
|
|
commands = map_obj_to_commands(want, have, module)
|
|
result['commands'] = commands
|
|
|
|
if commands:
|
|
if not module.check_mode:
|
|
for c in commands:
|
|
module.run_command(c, check_rc=True)
|
|
result['changed'] = True
|
|
|
|
module.exit_json(**result)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|