summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Hamilton <mhamilton@nicira.com>2015-07-09 00:36:30 -0700
committerMark Hamilton <mhamilton@nicira.com>2015-07-09 00:36:30 -0700
commit325ef12aeedc71d9e9da66aebbb66caaab64f9bf (patch)
tree4d82a4832a2bf0e3bcc73d028117cdff94b179cf
parent5713cc5ee9f9913c5a455a10a612502c5b1ecc72 (diff)
downloadansible-modules-extras-325ef12aeedc71d9e9da66aebbb66caaab64f9bf.tar.gz
Added support to assign attached mac address interface id and port options.
Updated code to pass pep8 v1.6.2 pylint v0.25.0.
-rw-r--r--network/openvswitch_port.py212
1 files changed, 196 insertions, 16 deletions
diff --git a/network/openvswitch_port.py b/network/openvswitch_port.py
index 6f59f4b1..bb392416 100644
--- a/network/openvswitch_port.py
+++ b/network/openvswitch_port.py
@@ -1,6 +1,8 @@
#!/usr/bin/python
#coding: utf-8 -*-
+# pylint: disable=C0111
+
# (c) 2013, David Stygstra <david.stygstra@gmail.com>
#
# This file is part of Ansible
@@ -17,6 +19,11 @@
#
# You should have received a copy of the GNU General Public License
# along with this software. If not, see <http://www.gnu.org/licenses/>.
+#
+# Portions copyright @ 2015 VMware, Inc. All rights reserved.
+
+import syslog
+import os
DOCUMENTATION = '''
---
@@ -47,44 +54,188 @@ options:
default: 5
description:
- How long to wait for ovs-vswitchd to respond
+ iface-id:
+ required: false
+ description:
+ - Used when port is created to set the external_ids:iface-id.
+ attached-mac:
+ required: false
+ description:
+ - MAC address when port is created using external_ids:attached-mac.
+ set:
+ required: false
+ description:
+ - Additional set options to apply to the port
'''
EXAMPLES = '''
# Creates port eth2 on bridge br-ex
- openvswitch_port: bridge=br-ex port=eth2 state=present
+
+# Creates port eth6 and set ofport equal to 6.
+- openvswitch_port: bridge=bridge-loop port=eth6 state=present
+ set Interface eth6 ofport_request=6
+
+# Assign interface id server1-vifeth6 and mac address 52:54:00:30:6d:11
+# to port vifeth6
+- openvswitch_port: bridge=br-int port=vifeth6 state=present
+ args:
+ external_ids:
+ iface-id: "server1-vifeth6"
+ attached-mac: "52:54:00:30:6d:11"
+
'''
+# pylint: disable=W0703
+
+
+def truncate_before(value, srch):
+ """ Return content of str before the srch parameters. """
+
+ before_index = value.find(srch)
+ if (before_index >= 0):
+ return value[:before_index]
+ else:
+ return value
+
+def _set_to_get(set_cmd):
+ """ Convert set command to get command and set value.
+ return tuple (get command, set value)
+ """
+
+ ##
+ # If set has option: then we want to truncate just before that.
+ set_cmd = truncate_before(set_cmd, " option:")
+ get_cmd = set_cmd.split(" ")
+ (key, value) = get_cmd[-1].split("=")
+ syslog.syslog(syslog.LOG_NOTICE, "get commands %s " % key)
+ return (["--", "get"] + get_cmd[:-1] + [key], value)
+
+
+# pylint: disable=R0902
class OVSPort(object):
+ """ Interface to OVS port. """
def __init__(self, module):
self.module = module
self.bridge = module.params['bridge']
self.port = module.params['port']
self.state = module.params['state']
self.timeout = module.params['timeout']
+ self.set_opt = module.params.get('set', None)
+
+ # if the port name starts with "vif", let's assume it's a VIF
+ self.is_vif = self.port.startswith('vif')
+
+ ##
+ # Several places need host name.
+ rtc, out, err = self.module.run_command(["hostname", "-s"])
+ if (rtc):
+ self.module.fail_json(msg=err)
+ self.hostname = out.strip("\n")
+
+ def _attached_mac_get(self):
+ """ Return the interface. """
+ attached_mac = self.module.params['external_ids'].get('attached-mac',
+ None)
+ if (not attached_mac):
+ attached_mac = "00:50:50:F"
+ attached_mac += self.hostname[-3] + ":"
+ attached_mac += self.hostname[-2:] + ":00"
+ return attached_mac
+
+ def _iface_id_get(self):
+ """ Return the interface id. """
+
+ iface_id = self.module.params['external_ids'].get('iface-id', None)
+ if (not iface_id):
+ iface_id = "%s-%s" % (self.hostname, self.port)
+ return iface_id
def _vsctl(self, command):
'''Run ovs-vsctl command'''
- return self.module.run_command(['ovs-vsctl', '-t', str(self.timeout)] + command)
+
+ cmd = ['ovs-vsctl', '-t', str(self.timeout)] + command
+ syslog.syslog(syslog.LOG_NOTICE, " ".join(cmd))
+ return self.module.run_command(cmd)
def exists(self):
'''Check if the port already exists'''
- rc, out, err = self._vsctl(['list-ports', self.bridge])
- if rc != 0:
- raise Exception(err)
+
+ (rtc, out, err) = self._vsctl(['list-ports', self.bridge])
+
+ if rtc != 0:
+ self.module.fail_json(msg=err)
+
return any(port.rstrip() == self.port for port in out.split('\n'))
+ def set(self, set_opt):
+ """ Set attributes on a port. """
+
+ syslog.syslog(syslog.LOG_NOTICE, "set called %s" % set_opt)
+ if (not set_opt):
+ return False
+
+ (get_cmd, set_value) = _set_to_get(set_opt)
+ (rtc, out, err) = self._vsctl(get_cmd)
+ if rtc != 0:
+ self.module.fail_json(msg=err)
+
+ out = out.strip("\n")
+ out = out.strip('"')
+ if (out == set_value):
+ return False
+
+ (rtc, out, err) = self._vsctl(["--", "set"] + set_opt.split(" "))
+ if rtc != 0:
+ self.module.fail_json(msg=err)
+ self.module.exit_json(changed=True)
+ syslog.syslog(syslog.LOG_NOTICE, "-- set %s" % set_opt)
+
+ def set_vif_attributes(self):
+ ''' Set attributes for a vif '''
+
+ ##
+ # create a fake MAC address for the VIF
+ fmac = self._attached_mac_get()
+
+ ##
+ # If vif_uuid is missing then construct a new one.
+ iface_id = self._iface_id_get()
+ syslog.syslog(syslog.LOG_NOTICE, "iface-id %s" % iface_id)
+
+ attached_mac = "external_ids:attached-mac=%s" % fmac
+ iface_id = "external_ids:iface-id=%s" % iface_id
+ vm_id = "external_ids:vm-id=%s" % self.hostname
+ cmd = ["set", "Interface", self.port,
+ "external_ids:iface-status=active", iface_id, vm_id,
+ attached_mac]
+
+ (rtc, _, stderr) = self._vsctl(cmd)
+ if rtc != 0:
+ self.module.fail_json(msg="%s returned %s %s" % (" ".join(cmd),
+ rtc, stderr))
+
def add(self):
'''Add the port'''
- rc, _, err = self._vsctl(['add-port', self.bridge, self.port])
- if rc != 0:
- raise Exception(err)
+ cmd = ['add-port', self.bridge, self.port]
+ if self.set and self.set_opt:
+ cmd += ["--", "set"]
+ cmd += self.set_opt.split(" ")
+
+ (rtc, _, err) = self._vsctl(cmd)
+ if rtc != 0:
+ self.module.fail_json(msg=err)
+ syslog.syslog(syslog.LOG_NOTICE, " ".join(cmd))
+
+ if self.is_vif:
+ self.set_vif_attributes()
def delete(self):
'''Remove the port'''
- rc, _, err = self._vsctl(['del-port', self.bridge, self.port])
- if rc != 0:
- raise Exception(err)
+ (rtc, _, err) = self._vsctl(['del-port', self.bridge, self.port])
+ if rtc != 0:
+ self.module.fail_json(msg=err)
def check(self):
'''Run check mode'''
@@ -95,8 +246,8 @@ class OVSPort(object):
changed = True
else:
changed = False
- except Exception, e:
- self.module.fail_json(msg=str(e))
+ except Exception, earg:
+ self.module.fail_json(msg=str(earg))
self.module.exit_json(changed=changed)
def run(self):
@@ -108,25 +259,50 @@ class OVSPort(object):
self.delete()
changed = True
elif self.state == 'present':
- if not self.exists():
+ ##
+ # Add any missing ports.
+ if (not self.exists()):
self.add()
changed = True
- except Exception, e:
- self.module.fail_json(msg=str(e))
+
+ ##
+ # If the -- set changed check here and make changes
+ # but this only makes sense when state=present.
+ if (not changed):
+ changed = self.set(self.set_opt) or changed
+ items = self.module.params['external_ids'].items()
+ for (key, value) in items:
+ value = value.replace('"', '')
+ fmt_opt = "Interface %s external_ids:%s=%s"
+ external_id = fmt_opt % (self.port, key, value)
+ syslog.syslog(syslog.LOG_NOTICE,
+ "external %s" % external_id)
+ changed = self.set(external_id) or changed
+ ##
+ except Exception, earg:
+ self.module.fail_json(msg=str(earg))
self.module.exit_json(changed=changed)
+# pylint: disable=E0602
def main():
+ """ Entry point. """
module = AnsibleModule(
argument_spec={
'bridge': {'required': True},
'port': {'required': True},
'state': {'default': 'present', 'choices': ['present', 'absent']},
- 'timeout': {'default': 5, 'type': 'int'}
+ 'timeout': {'default': 5, 'type': 'int'},
+ 'set': {'required': False},
+ 'external_ids': {'default': {}, 'required': False},
+ 'syslogging': {'required': False, 'type': "bool", 'default': True}
},
supports_check_mode=True,
)
+ if (module.params["syslogging"]):
+ syslog.openlog('ansible-%s' % os.path.basename(__file__))
+
port = OVSPort(module)
if module.check_mode:
port.check()
@@ -134,6 +310,10 @@ def main():
port.run()
+# pylint: disable=W0614
+# pylint: disable=W0401
+# pylint: disable=W0622
+
# import module snippets
from ansible.module_utils.basic import *
main()