Vendor openvswitch_bridge
The upstream openvswitch collection has been deprecated and was not included in newer Ansible (like Ansible 11). Vendor the openvswitch_bridge module from that collection as we use it for multinode bridge setups. The code was fetched from: https://raw.githubusercontent.com/ansible-collections/openvswitch.openvswitch/d375078cfd942599c42fe28e46f59f063c9d3a9d/plugins/modules/openvswitch_bridge.py And is currently unmodified except for removal of the shebang (to make linter rules happy), flake8: noqa at the file level (to disable python linter checks), and a new comment block explaining why the code was vendored and where it originated from. A warning is added to the role README indicating that this role is now effectively deprecated due to its dependencies. An alternative approach that should be easier to maintain long term is suggested as well. Change-Id: I2c90d3145b50498b4759046d43b02f70c10715e7
This commit is contained in:
@@ -1,3 +1,18 @@
|
||||
.. warning::
|
||||
This role currently depends on openvswitch and the now deprecated by
|
||||
Ansible openvswitch_bridge module. This transitively means this role is
|
||||
effectively deprecated as well. In order to get around the deprecation
|
||||
and removal of this Ansible module we have vendored it in this role. This
|
||||
may not work with future versions of Ansible
|
||||
|
||||
Ideally we would rewrite the role to use Linux bridges instead of
|
||||
openvswitch as this set of tooling is more readily available and common
|
||||
on Linux machines. We could continue to use VXLAN with Linux bridge or
|
||||
consider switching to GENEVE or maybe even Wireguard as alternative
|
||||
overlay methods during that switch.
|
||||
|
||||
Help is very much appreciated to make this rewrite happen.
|
||||
|
||||
Configures a VXLAN virtual network overlay through an openvswitch network
|
||||
bridge between a 'switch' node and 'peer' nodes.
|
||||
|
||||
|
||||
0
roles/multi-node-bridge/library/__init__.py
Normal file
0
roles/multi-node-bridge/library/__init__.py
Normal file
296
roles/multi-node-bridge/library/openvswitch_bridge.py
Normal file
296
roles/multi-node-bridge/library/openvswitch_bridge.py
Normal file
@@ -0,0 +1,296 @@
|
||||
# flake8: noqa
|
||||
|
||||
# (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)
|
||||
|
||||
# This code originates from the openvswitch ansible collection. This collection
|
||||
# was deprecated and not included in Ansible 11. We vendor it here so that
|
||||
# we can continue to use it against newer Ansible. This code was retrieved
|
||||
# from:
|
||||
# https://raw.githubusercontent.com/ansible-collections/openvswitch.openvswitch/d375078cfd942599c42fe28e46f59f063c9d3a9d/plugins/modules/openvswitch_bridge.py
|
||||
# The only modifications made to the original code are the removal of the
|
||||
# shebang at the top of the file (we check that with an explicit command),
|
||||
# the addition of flake8: noqa at the file level to disable all python linter
|
||||
# checks, and the inclusion of this explanatory comment block.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
DOCUMENTATION = """
|
||||
module: openvswitch_bridge
|
||||
author: David Stygstra (@stygstra)
|
||||
short_description: Manage Open vSwitch bridges
|
||||
requirements:
|
||||
- ovs-vsctl
|
||||
description:
|
||||
- Manage Open vSwitch bridges
|
||||
version_added: 1.0.0
|
||||
options:
|
||||
bridge:
|
||||
required: true
|
||||
description:
|
||||
- Name of bridge or fake bridge to manage
|
||||
type: str
|
||||
parent:
|
||||
description:
|
||||
- Bridge parent of the fake bridge to manage
|
||||
type: str
|
||||
vlan:
|
||||
description:
|
||||
- The VLAN id of the fake bridge to manage (must be between 0 and 4095). This
|
||||
parameter is required if I(parent) parameter is set.
|
||||
type: int
|
||||
state:
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
description:
|
||||
- Whether the bridge should exist
|
||||
type: str
|
||||
timeout:
|
||||
default: 5
|
||||
description:
|
||||
- How long to wait for ovs-vswitchd to respond
|
||||
type: int
|
||||
external_ids:
|
||||
description:
|
||||
- A dictionary of external-ids. Omitting this parameter is a No-op. To clear
|
||||
all external-ids pass an empty value.
|
||||
type: dict
|
||||
fail_mode:
|
||||
description:
|
||||
- Set bridge fail-mode. The default value (None) is a No-op.
|
||||
type: str
|
||||
set:
|
||||
description:
|
||||
- Run set command after bridge configuration. This parameter is non-idempotent,
|
||||
play will always return I(changed) state if present
|
||||
type: str
|
||||
database_socket:
|
||||
description:
|
||||
- Path/ip to datbase socket to use
|
||||
- Default path is used if not specified
|
||||
- Path should start with 'unix:' prefix
|
||||
type: str
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
# Create a bridge named br-int
|
||||
- openvswitch.openvswitch.openvswitch_bridge:
|
||||
bridge: br-int
|
||||
state: present
|
||||
|
||||
# Create a fake bridge named br-int within br-parent on the VLAN 405
|
||||
- openvswitch.openvswitch.openvswitch_bridge:
|
||||
bridge: br-int
|
||||
parent: br-parent
|
||||
vlan: 405
|
||||
state: present
|
||||
|
||||
# Create an integration bridge
|
||||
- openvswitch.openvswitch.openvswitch_bridge:
|
||||
bridge: br-int
|
||||
state: present
|
||||
fail_mode: secure
|
||||
args:
|
||||
external_ids:
|
||||
bridge-id: br-int
|
||||
# Create a bridge named br0 in database with socket at /opt/second.sock
|
||||
- openvswitch.openvswitch.openvswitch_bridge:
|
||||
bridge: br0
|
||||
state: present
|
||||
database_socket: unix:/opt/second.sock
|
||||
"""
|
||||
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.six import iteritems
|
||||
|
||||
|
||||
def _fail_mode_to_str(text):
|
||||
if not text:
|
||||
return None
|
||||
else:
|
||||
return text.strip()
|
||||
|
||||
|
||||
def _external_ids_to_dict(text):
|
||||
if not text:
|
||||
return None
|
||||
else:
|
||||
d = {}
|
||||
|
||||
for l in text.splitlines():
|
||||
if l:
|
||||
k, v = l.split("=")
|
||||
d[k] = v
|
||||
|
||||
return d
|
||||
|
||||
|
||||
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-br %(bridge)s"
|
||||
command = templatized_command % module.params
|
||||
commands.append(command)
|
||||
else:
|
||||
if have:
|
||||
if want["fail_mode"] != have["fail_mode"]:
|
||||
templatized_command = (
|
||||
"%(ovs-vsctl)s -t %(timeout)s set-fail-mode %(bridge)s %(fail_mode)s"
|
||||
)
|
||||
command = templatized_command % module.params
|
||||
commands.append(command)
|
||||
|
||||
if want["external_ids"] != have["external_ids"]:
|
||||
templatized_command = "%(ovs-vsctl)s -t %(timeout)s br-set-external-id %(bridge)s"
|
||||
command = templatized_command % module.params
|
||||
if want["external_ids"]:
|
||||
for k, v in iteritems(want["external_ids"]):
|
||||
if (
|
||||
k not in have["external_ids"]
|
||||
or want["external_ids"][k] != have["external_ids"][k]
|
||||
):
|
||||
command += " " + k + " " + v
|
||||
commands.append(command)
|
||||
|
||||
if want["vlan"] and to_text(want["vlan"]) != have["vlan"]:
|
||||
templatized_command = (
|
||||
"%(ovs-vsctl)s -t %(timeout)s set port %(bridge)s tag=%(vlan)s"
|
||||
)
|
||||
command = templatized_command % module.params
|
||||
commands.append(command)
|
||||
else:
|
||||
templatized_command = "%(ovs-vsctl)s -t %(timeout)s add-br %(bridge)s"
|
||||
command = templatized_command % module.params
|
||||
|
||||
if want["parent"]:
|
||||
templatized_command = "%(parent)s %(vlan)s"
|
||||
command += " " + templatized_command % module.params
|
||||
|
||||
if want["set"]:
|
||||
templatized_command = " -- set %(set)s"
|
||||
command += templatized_command % module.params
|
||||
|
||||
commands.append(command)
|
||||
|
||||
if want["fail_mode"]:
|
||||
templatized_command = (
|
||||
"%(ovs-vsctl)s -t %(timeout)s set-fail-mode %(bridge)s %(fail_mode)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 br-set-external-id %(bridge)s"
|
||||
)
|
||||
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-br"
|
||||
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["bridge"] in out.splitlines():
|
||||
obj["bridge"] = module.params["bridge"]
|
||||
|
||||
templatized_command = "%(ovs-vsctl)s -t %(timeout)s br-to-parent %(bridge)s"
|
||||
command = templatized_command % module.params
|
||||
rc, out, err = module.run_command(command, check_rc=True)
|
||||
obj["parent"] = out.strip()
|
||||
|
||||
templatized_command = "%(ovs-vsctl)s -t %(timeout)s br-to-vlan %(bridge)s"
|
||||
command = templatized_command % module.params
|
||||
rc, out, err = module.run_command(command, check_rc=True)
|
||||
obj["vlan"] = out.strip()
|
||||
|
||||
templatized_command = "%(ovs-vsctl)s -t %(timeout)s get-fail-mode %(bridge)s"
|
||||
command = templatized_command % module.params
|
||||
rc, out, err = module.run_command(command, check_rc=True)
|
||||
obj["fail_mode"] = _fail_mode_to_str(out)
|
||||
|
||||
templatized_command = "%(ovs-vsctl)s -t %(timeout)s br-get-external-id %(bridge)s"
|
||||
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"],
|
||||
"parent": module.params["parent"],
|
||||
"vlan": module.params["vlan"],
|
||||
"fail_mode": module.params["fail_mode"],
|
||||
"external_ids": module.params["external_ids"],
|
||||
"set": module.params["set"],
|
||||
}
|
||||
|
||||
return obj
|
||||
|
||||
|
||||
def main():
|
||||
"""Entry point."""
|
||||
argument_spec = {
|
||||
"bridge": {"required": True},
|
||||
"parent": {"default": None},
|
||||
"vlan": {"default": None, "type": "int"},
|
||||
"state": {"default": "present", "choices": ["present", "absent"]},
|
||||
"timeout": {"default": 5, "type": "int"},
|
||||
"external_ids": {"default": None, "type": "dict"},
|
||||
"fail_mode": {"default": None},
|
||||
"set": {"required": False, "default": None},
|
||||
"database_socket": {"default": None},
|
||||
}
|
||||
|
||||
required_if = [("parent", not None, ("vlan",))]
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
required_if=required_if,
|
||||
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)
|
||||
if module.params.get("database_socket"):
|
||||
module.params["ovs-vsctl"] += " --db=" + module.params.get("database_socket")
|
||||
|
||||
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()
|
||||
Reference in New Issue
Block a user