The ovn-docker files were not updated for a very long time apart from treewide adjustments. Let's remove the ovn-docker utility files.
Signed-off-by: Ales Musil <[email protected]> --- Documentation/automake.mk | 2 - Documentation/howto/docker.rst | 323 --------- Documentation/howto/index.rst | 2 - Documentation/howto/openstack-containers.rst | 135 ---- Documentation/intro/install/fedora.rst | 2 +- NEWS | 1 + debian/.gitignore | 1 - rhel/ovn-fedora.spec.in | 14 - utilities/.gitignore | 2 - utilities/automake.mk | 6 - utilities/ovn-docker-overlay-driver.in | 442 ------------ utilities/ovn-docker-underlay-driver.in | 677 ------------------- 12 files changed, 2 insertions(+), 1605 deletions(-) delete mode 100644 Documentation/howto/docker.rst delete mode 100644 Documentation/howto/openstack-containers.rst delete mode 100755 utilities/ovn-docker-overlay-driver.in delete mode 100755 utilities/ovn-docker-underlay-driver.in diff --git a/Documentation/automake.mk b/Documentation/automake.mk index b8187607e..79156fae0 100644 --- a/Documentation/automake.mk +++ b/Documentation/automake.mk @@ -38,11 +38,9 @@ DOC_SOURCE = \ Documentation/topics/vif-plug-providers/index.rst \ Documentation/topics/vif-plug-providers/vif-plug-providers.rst \ Documentation/howto/index.rst \ - Documentation/howto/docker.rst \ Documentation/howto/firewalld.rst \ Documentation/howto/ipsec.rst \ Documentation/howto/ssl.rst \ - Documentation/howto/openstack-containers.rst \ Documentation/ref/index.rst \ Documentation/faq/index.rst \ Documentation/faq/contributing.rst \ diff --git a/Documentation/howto/docker.rst b/Documentation/howto/docker.rst deleted file mode 100644 index 1ada1fa2c..000000000 --- a/Documentation/howto/docker.rst +++ /dev/null @@ -1,323 +0,0 @@ -.. - Licensed under the Apache License, Version 2.0 (the "License"); you may - not use this file except in compliance with the License. You may obtain - a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - License for the specific language governing permissions and limitations - under the License. - - Convention for heading levels in OVN documentation: - - ======= Heading 0 (reserved for the title in a document) - ------- Heading 1 - ~~~~~~~ Heading 2 - +++++++ Heading 3 - ''''''' Heading 4 - - Avoid deeper levels because they do not render well. - -=================================== -Open Virtual Networking With Docker -=================================== - -This document describes how to use Open Virtual Networking with Docker 1.9.0 -or later. - -.. important:: - - Requires Docker version 1.9.0 or later. Only Docker 1.9.0+ comes with support - for multi-host networking. Consult www.docker.com for instructions on how to - install Docker. - -.. note:: - - You must build and install Open vSwitch before proceeding with the below - guide. Refer to :doc:`/intro/install/index` for more information. - -Setup ------ - -For multi-host networking with OVN and Docker, Docker has to be started with a -distributed key-value store. For example, if you decide to use consul as your -distributed key-value store and your host IP address is ``$HOST_IP``, start -your Docker daemon with:: - - $ docker daemon --cluster-store=consul://127.0.0.1:8500 \ - --cluster-advertise=$HOST_IP:0 - -OVN provides network virtualization to containers. OVN's integration with -Docker currently works in two modes - the "underlay" mode or the "overlay" -mode. - -In the "underlay" mode, OVN requires a OpenStack setup to provide container -networking. In this mode, one can create logical networks and can have -containers running inside VMs, standalone VMs (without having any containers -running inside them) and physical machines connected to the same logical -network. This is a multi-tenant, multi-host solution. - -In the "overlay" mode, OVN can create a logical network amongst containers -running on multiple hosts. This is a single-tenant (extendable to multi-tenants -depending on the security characteristics of the workloads), multi-host -solution. In this mode, you do not need a pre-created OpenStack setup. - -For both the modes to work, a user has to install and start Open vSwitch in -each VM/host that they plan to run their containers on. - -.. _docker-overlay: - -The "overlay" mode ------------------- - -.. note:: - - OVN in "overlay" mode needs a minimum Open vSwitch version of 2.5. - -1. Start the central components. - - OVN architecture has a central component which stores your networking intent - in a database. On one of your machines, with an IP Address of - ``$CENTRAL_IP``, where you have installed and started Open vSwitch, you will - need to start some central components. - - Start ovn-northd daemon. This daemon translates networking intent from Docker - stored in the OVN\_Northbound database to logical flows in ``OVN_Southbound`` - database. For example:: - - $ /usr/share/ovn/scripts/ovn-ctl start_northd - - With Open vSwitch version of 2.7 or greater, you need to run the following - additional commands (Please read the manpages of ovn-nb for more control - on the types of connection allowed.) :: - - $ ovn-nbctl set-connection ptcp:6641 - $ ovn-sbctl set-connection ptcp:6642 - -2. One time setup - - On each host, where you plan to spawn your containers, you will need to run - the below command once. You may need to run it again if your OVS database - gets cleared. It is harmless to run it again in any case:: - - $ ovs-vsctl set Open_vSwitch . \ - external_ids:ovn-remote="tcp:$CENTRAL_IP:6642" \ - external_ids:ovn-nb="tcp:$CENTRAL_IP:6641" \ - external_ids:ovn-encap-ip=$LOCAL_IP \ - external_ids:ovn-encap-type="$ENCAP_TYPE" - - where: - - ``$LOCAL_IP`` - is the IP address via which other hosts can reach this host. This acts as - your local tunnel endpoint. - - ``$ENCAP_TYPE`` - is the type of tunnel that you would like to use for overlay networking. - The options are ``geneve`` or ``vxlan``. Your kernel must have support for - your chosen ``$ENCAP_TYPE``. You will need a minimum Linux kernel version - of 3.18 for ``geneve``. You can verify whether you have the support in - your kernel as follows:: - - $ lsmod | grep $ENCAP_TYPE - - In addition, each Open vSwitch instance in an OVN deployment needs a unique, - persistent identifier, called the ``system-id``. If you install OVS from - distribution packaging for Open vSwitch (e.g. .deb or .rpm packages), or if - you use the ovs-ctl utility included with Open vSwitch, it automatically - configures a system-id. If you start Open vSwitch manually, you should set - one up yourself. For example:: - - $ id_file=/etc/openvswitch/system-id.conf - $ test -e $id_file || uuidgen > $id_file - $ ovs-vsctl set Open_vSwitch . external_ids:system-id=$(cat $id_file) - -3. Start the ``ovn-controller``. - - You need to run the below command on every boot:: - - $ /usr/share/ovn/scripts/ovn-ctl start_controller - -4. Start the Open vSwitch network driver. - - By default Docker uses Linux bridge for networking. But it has support for - external drivers. To use Open vSwitch instead of the Linux bridge, you will - need to start the Open vSwitch driver. - - The Open vSwitch driver uses the Python's flask module to listen to Docker's - networking api calls. So, if your host does not have Python's flask module, - install it:: - - $ sudo pip install Flask - - Start the Open vSwitch driver on every host where you plan to create your - containers. Refer to the note on ``$OVS_PYTHON_LIBS_PATH`` that is used below - at the end of this document:: - - $ PYTHONPATH=$OVS_PYTHON_LIBS_PATH ovn-docker-overlay-driver --detach - - .. note:: - - The ``$OVS_PYTHON_LIBS_PATH`` variable should point to the directory where - Open vSwitch Python modules are installed. If you installed Open vSwitch - Python modules via the Debian package of ``python-openvswitch`` or via pip - by running ``pip install ovs``, you do not need to specify the PATH. If - you installed it by following the instructions in - :doc:`/intro/install/general`, then you should specify the PATH. In this - case, the PATH depends on the options passed to ``./configure``. It is - usually either ``/usr/share/openvswitch/python`` or - ``/usr/local/share/openvswitch/python`` - -Docker has inbuilt primitives that closely match OVN's logical switches and -logical port concepts. Consult Docker's documentation for all the possible -commands. Here are some examples. - -Create a logical switch -~~~~~~~~~~~~~~~~~~~~~~~ - -To create a logical switch with name 'foo', on subnet '192.168.1.0/24', run:: - - $ NID=`docker network create -d openvswitch --subnet=192.168.1.0/24 foo` - -List all logical switches -~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - $ docker network ls - -You can also look at this logical switch in OVN's northbound database by -running the following command:: - - $ ovn-nbctl --db=tcp:$CENTRAL_IP:6640 ls-list - -Delete a logical switch -~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - $ docker network rm bar - - -Create a logical port -~~~~~~~~~~~~~~~~~~~~~ - -Docker creates your logical port and attaches it to the logical network in a -single step. For example, to attach a logical port to network ``foo`` inside -container busybox, run:: - - $ docker run -itd --net=foo --name=busybox busybox - -List all logical ports -~~~~~~~~~~~~~~~~~~~~~~ - -Docker does not currently have a CLI command to list all logical ports but you -can look at them in the OVN database by running:: - - $ ovn-nbctl --db=tcp:$CENTRAL_IP:6640 lsp-list $NID - -Create and attach a logical port to a running container -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - $ docker network create -d openvswitch --subnet=192.168.2.0/24 bar - $ docker network connect bar busybox - -Detach and delete a logical port from a running container -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -You can delete your logical port and detach it from a running container -by running: - -:: - - $ docker network disconnect bar busybox - -.. _docker-underlay: - -The "underlay" mode -------------------- - -.. note:: - - This mode requires that you have a OpenStack setup pre-installed with - OVN providing the underlay networking. - -1. One time setup - - A OpenStack tenant creates a VM with a single network interface (or multiple) - that belongs to management logical networks. The tenant needs to fetch the - port-id associated with the interface via which he plans to send the container - traffic inside the spawned VM. This can be obtained by running the below - command to fetch the 'id' associated with the VM:: - - $ nova list - - and then by running:: - - $ neutron port-list --device_id=$id - - Inside the VM, download the OpenStack RC file that contains the tenant - information (henceforth referred to as ``openrc.sh``). Edit the file and add the - previously obtained port-id information to the file by appending the following - line:: - - $ export OS_VIF_ID=$port_id - - After this edit, the file will look something like:: - - #!/bin/bash - export OS_AUTH_URL=http://10.33.75.122:5000/v2.0 - export OS_TENANT_ID=fab106b215d943c3bad519492278443d - export OS_TENANT_NAME="demo" - export OS_USERNAME="demo" - export OS_VIF_ID=e798c371-85f4-4f2d-ad65-d09dd1d3c1c9 - -2. Create the Open vSwitch bridge - - If your VM has one ethernet interface (e.g.: 'eth0'), you will need to add - that device as a port to an Open vSwitch bridge 'breth0' and move its IP - address and route related information to that bridge. (If it has multiple - network interfaces, you will need to create and attach an Open vSwitch - bridge for the interface via which you plan to send your container - traffic.) - - If you use DHCP to obtain an IP address, then you should kill the DHCP - client that was listening on the physical Ethernet interface (e.g. eth0) and - start one listening on the Open vSwitch bridge (e.g. breth0). - - Depending on your VM, you can make the above step persistent across reboots. - For example, if your VM is Debian/Ubuntu-based, read - `openvswitch-switch.README.Debian` found in `debian` folder. If your VM is - RHEL-based, refer to :doc:`/intro/install/fedora`. - -3. Start the Open vSwitch network driver - - The Open vSwitch driver uses the Python's flask module to listen to Docker's - networking api calls. The driver also uses OpenStack's - ``python-neutronclient`` libraries. If your host does not have Python's - ``flask`` module or ``python-neutronclient`` you must install them. For - example:: - - $ pip install python-neutronclient - $ pip install Flask - - Once installed, source the ``openrc`` file:: - - $ . ./openrc.sh - - Start the network driver and provide your OpenStack tenant password when - prompted:: - - $ PYTHONPATH=$OVS_PYTHON_LIBS_PATH ovn-docker-underlay-driver \ - --bridge breth0 --detach - -From here-on you can use the same Docker commands as described in -`docker-overlay`_. - -Refer to the ovs-architecture man pages (``man ovn-architecture``) to -understand OVN's architecture in detail. diff --git a/Documentation/howto/index.rst b/Documentation/howto/index.rst index 6f6c59482..dab3058be 100644 --- a/Documentation/howto/index.rst +++ b/Documentation/howto/index.rst @@ -45,6 +45,4 @@ OVN .. toctree:: :maxdepth: 1 - docker - openstack-containers firewalld diff --git a/Documentation/howto/openstack-containers.rst b/Documentation/howto/openstack-containers.rst deleted file mode 100644 index b6911d19e..000000000 --- a/Documentation/howto/openstack-containers.rst +++ /dev/null @@ -1,135 +0,0 @@ -.. - Licensed under the Apache License, Version 2.0 (the "License"); you may - not use this file except in compliance with the License. You may obtain - a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - License for the specific language governing permissions and limitations - under the License. - - Convention for heading levels in OVN documentation: - - ======= Heading 0 (reserved for the title in a document) - ------- Heading 1 - ~~~~~~~ Heading 2 - +++++++ Heading 3 - ''''''' Heading 4 - - Avoid deeper levels because they do not render well. - -================================================ -Integration of Containers with OVN and OpenStack -================================================ - -Isolation between containers is weaker than isolation between VMs, so some -environments deploy containers for different tenants in separate VMs as an -additional security measure. This document describes creation of containers -inside VMs and how they can be made part of the logical networks securely. The -created logical network can include VMs, containers and physical machines as -endpoints. To better understand the proposed integration of containers with -OVN and OpenStack, this document describes the end to end workflow with an -example. - -* A OpenStack tenant creates a VM (say VM-A) with a single network interface - that belongs to a management logical network. The VM is meant to host - containers. OpenStack Nova chooses the hypervisor on which VM-A is created. - -* A Neutron port may have been created in advance and passed in to Nova with - the request to create a new VM. If not, Nova will issue a request to Neutron - to create a new port. The ID of the logical port from Neutron will also be - used as the vif-id for the virtual network interface (VIF) of VM-A. - -* When VM-A is created on a hypervisor, its VIF gets added to the Open vSwitch - integration bridge. This creates a row in the Interface table of the - ``Open_vSwitch`` database. As explained in the :doc:`integration guide - </topics/integration>`, the vif-id associated with the VM network interface - gets added in the ``external_ids:iface-id`` column of the newly created row - in the Interface table. - -* Since VM-A belongs to a logical network, it gets an IP address. This IP - address is used to spawn containers (either manually or through container - orchestration systems) inside that VM and to monitor the health of the - created containers. - -* The vif-id associated with the VM's network interface can be obtained by - making a call to Neutron using tenant credentials. - -* This flow assumes a component called a "container network plugin". If you - take Docker as an example for containers, you could envision the plugin to be - either a wrapper around Docker or a feature of Docker itself that understands - how to perform part of this workflow to get a container connected to a - logical network managed by Neutron. The rest of the flow refers to this - logical component that does not yet exist as the "container network plugin". - -* All the calls to Neutron will need tenant credentials. These calls can - either be made from inside the tenant VM as part of a container network - plugin or from outside the tenant VM (if the tenant is not comfortable using - temporary Keystone tokens from inside the tenant VMs). For simplicity, this - document explains the work flow using the former method. - -* The container hosting VM will need Open vSwitch installed in it. The only - work for Open vSwitch inside the VM is to tag network traffic coming from - containers. - -* When a container needs to be created inside the VM with a container network - interface that is expected to be attached to a particular logical switch, the - network plugin in that VM chooses any unused VLAN (This VLAN tag only needs - to be unique inside that VM. This limits the number of container interfaces - to 4096 inside a single VM). This VLAN tag is stripped out in the hypervisor - by OVN and is only useful as a context (or metadata) for OVN. - -* The container network plugin then makes a call to Neutron to create a logical - port. In addition to all the inputs that a call to create a port in Neutron - that are currently needed, it sends the vif-id and the VLAN tag as inputs. - -* Neutron in turn will verify that the vif-id belongs to the tenant in question - and then uses the OVN specific plugin to create a new row in the - Logical_Switch_Port table of the OVN Northbound Database. Neutron responds - back with an IP address and MAC address for that network interface. So - Neutron becomes the IPAM system and provides unique IP and MAC addresses - across VMs and containers in the same logical network. - -* The Neutron API call above to create a logical port for the container could - add a relatively significant amount of time to container creation. However, - an optimization is possible here. Logical ports could be created in advance - and reused by the container system doing container orchestration. Additional - Neutron API calls would only be needed if the port needs to be attached to a - different logical network. - -* When a container is eventually deleted, the network plugin in that VM may - make a call to Neutron to delete that port. Neutron in turn will delete the - entry in the ``Logical_Switch_Port`` table of the OVN Northbound Database. - -As an example, consider Docker containers. Since Docker currently does not -have a network plugin feature, this example uses a hypothetical wrapper around -Docker to make calls to Neutron. - -* Create a Logical switch:: - - $ ovn-docker --cred=cca86bd13a564ac2a63ddf14bf45d37f create network LS1 - - The above command will make a call to Neutron with the credentials to create - a logical switch. The above is optional if the logical switch has already - been created from outside the VM. - -* List networks available to the tenant:: - - $ ovn-docker --cred=cca86bd13a564ac2a63ddf14bf45d37f list networks - -* Create a container and attach a interface to the previously created switch as - a logical port:: - - $ ovn-docker --cred=cca86bd13a564ac2a63ddf14bf45d37f --vif-id=$VIF_ID \ - --network=LS1 run -d --net=none ubuntu:14.04 /bin/sh -c \ - "while true; do echo hello world; sleep 1; done" - - The above command will make a call to Neutron with all the inputs it - currently needs to create a logical port. In addition, it passes the $VIF_ID - and a unused VLAN. Neutron will add that information in OVN and return back - a MAC address and IP address for that interface. ovn-docker will then create - a veth pair, insert one end inside the container as 'eth0' and the other end - as a port of a local OVS bridge as an access port of the chosen VLAN. diff --git a/Documentation/intro/install/fedora.rst b/Documentation/intro/install/fedora.rst index b1d2ea5df..b6ee88a4f 100644 --- a/Documentation/intro/install/fedora.rst +++ b/Documentation/intro/install/fedora.rst @@ -109,7 +109,7 @@ Then execute the following from the OVN source directory (in which $ make rpm-fedora This will create the RPMs ``ovn``, ``ovn-central``, ``ovn-host``, -``ovn-vtep``, ``ovn-docker``, and ``ovn-br-controller``, along with +``ovn-vtep``, and ``ovn-br-controller``, along with their debuginfo variants. You can also have the above commands automatically run the OVN unit diff --git a/NEWS b/NEWS index 3b41042b6..7f94d0b14 100644 --- a/NEWS +++ b/NEWS @@ -18,6 +18,7 @@ Post v26.09.0 obsolete. - Removed OVN's ovs-bugtool plugin and helper scripts. - Removed ovn-sim utility scripts. + - Removed ovn-docker utility scripts. OVN v26.09.0 - xxx xx xxxx -------------------------- diff --git a/debian/.gitignore b/debian/.gitignore index 8873d381c..2fd03d861 100644 --- a/debian/.gitignore +++ b/debian/.gitignore @@ -10,5 +10,4 @@ /ovn-controller-vtep /ovn-host /ovn-central -/ovn-docker /tmp diff --git a/rhel/ovn-fedora.spec.in b/rhel/ovn-fedora.spec.in index e70c581e7..8c8b96050 100644 --- a/rhel/ovn-fedora.spec.in +++ b/rhel/ovn-fedora.spec.in @@ -111,16 +111,6 @@ Provides: openvswitch-ovn-vtep = %{?epoch:%{epoch}:}%{version}-%{release} %description vtep OVN vtep controller -%package docker -Summary: Open Virtual Network support -License: ASL 2.0 -Requires: ovn python3-openvswitch -Obsoletes: openvswitch-ovn-docker -Provides: openvswitch-ovn-docker = %{?epoch:%{epoch}:}%{version}-%{release} - -%description docker -Docker network plugins for OVN. - %package br-controller Summary: Open Virtual Network support License: ASL 2.0 @@ -528,10 +518,6 @@ fi %config(noreplace) %{_sysconfdir}/logrotate.d/ovn %{_unitdir}/[email protected] -%files docker -%{_bindir}/ovn-docker-overlay-driver -%{_bindir}/ovn-docker-underlay-driver - %files central %{_bindir}/ovn-northd %{_bindir}/ovn-ic diff --git a/utilities/.gitignore b/utilities/.gitignore index eb98594b7..fa1bc272b 100644 --- a/utilities/.gitignore +++ b/utilities/.gitignore @@ -16,6 +16,4 @@ /ovn-detrace.1 /ovn-debug /ovn-debug.8 -/ovn-docker-overlay-driver -/ovn-docker-underlay-driver /ovn-lib diff --git a/utilities/automake.mk b/utilities/automake.mk index 7d3f320dc..edf3fe9cd 100644 --- a/utilities/automake.mk +++ b/utilities/automake.mk @@ -18,16 +18,12 @@ MAN_ROOTS += \ utilities/ovn-detrace.1.in bin_SCRIPTS += \ - utilities/ovn-docker-overlay-driver \ - utilities/ovn-docker-underlay-driver \ utilities/ovn_detrace.py EXTRA_DIST += \ utilities/ovn-ctl \ utilities/ovn-lib.in \ utilities/ovn-ctl.8.xml \ - utilities/ovn-docker-overlay-driver.in \ - utilities/ovn-docker-underlay-driver.in \ utilities/ovn-nbctl.8.xml \ utilities/ovn-sbctl.8.xml \ utilities/ovn-ic-nbctl.8.xml \ @@ -48,8 +44,6 @@ EXTRA_DIST += \ CLEANFILES += \ utilities/ovn-ctl.8 \ utilities/ovn-lib \ - utilities/ovn-docker-overlay-driver \ - utilities/ovn-docker-underlay-driver \ utilities/ovn-nbctl.8 \ utilities/ovn-sbctl.8 \ utilities/ovn-ic-nbctl.8 \ diff --git a/utilities/ovn-docker-overlay-driver.in b/utilities/ovn-docker-overlay-driver.in deleted file mode 100755 index f408bbdd8..000000000 --- a/utilities/ovn-docker-overlay-driver.in +++ /dev/null @@ -1,442 +0,0 @@ -#! @PYTHON3@ -# Copyright (C) 2015 Nicira, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import argparse -import ast -import atexit -import json -import os -import random -import re -import shlex -import subprocess -import sys - -import ovs.dirs -import ovs.util -import ovs.daemon -import ovs.vlog - -from flask import Flask, jsonify -from flask import request, abort - -app = Flask(__name__) -vlog = ovs.vlog.Vlog("ovn-docker-overlay-driver") - -OVN_BRIDGE = "br-int" -OVN_NB = "" -PLUGIN_DIR = "/etc/docker/plugins" -PLUGIN_FILE = "/etc/docker/plugins/openvswitch.spec" - - -def call_popen(cmd): - child = subprocess.Popen(cmd, stdout=subprocess.PIPE) - output = child.communicate() - if child.returncode: - raise RuntimeError("Fatal error executing %s" % (cmd)) - if len(output) == 0 or output[0] == None: - output = "" - else: - output = output[0].strip() - return output - - -def call_prog(prog, args_list): - cmd = [prog, "--timeout=5", "-vconsole:off"] + args_list - return call_popen(cmd) - - -def ovs_vsctl(*args): - return call_prog("ovs-vsctl", list(args)) - - -def ovn_nbctl(*args): - args_list = list(args) - database_option = "%s=%s" % ("--db", OVN_NB) - args_list.insert(0, database_option) - return call_prog("ovn-nbctl", args_list) - - -def cleanup(): - if os.path.isfile(PLUGIN_FILE): - os.remove(PLUGIN_FILE) - - -def ovn_init_overlay(): - br_list = ovs_vsctl("list-br").split() - if OVN_BRIDGE not in br_list: - ovs_vsctl("--", "--may-exist", "add-br", OVN_BRIDGE, - "--", "set", "bridge", OVN_BRIDGE, - "external_ids:bridge-id=" + OVN_BRIDGE, - "other-config:disable-in-band=true", "fail-mode=secure") - - global OVN_NB - OVN_NB = ovs_vsctl("get", "Open_vSwitch", ".", - "external_ids:ovn-nb").strip('"') - if not OVN_NB: - sys.exit("OVN central database's ip address not set") - - ovs_vsctl("set", "open_vswitch", ".", - "external_ids:ovn-bridge=" + OVN_BRIDGE) - - -def prepare(): - parser = argparse.ArgumentParser() - - ovs.vlog.add_args(parser) - ovs.daemon.add_args(parser) - args = parser.parse_args() - ovs.vlog.handle_args(args) - ovs.daemon.handle_args(args) - ovn_init_overlay() - - if not os.path.isdir(PLUGIN_DIR): - os.makedirs(PLUGIN_DIR) - - ovs.daemon.daemonize() - try: - fo = open(PLUGIN_FILE, "w") - fo.write("tcp://0.0.0.0:5000") - fo.close() - except Exception as e: - ovs.util.ovs_fatal(0, "Failed to write to spec file (%s)" % str(e), - vlog) - - atexit.register(cleanup) - - [email protected]('/Plugin.Activate', methods=['POST']) -def plugin_activate(): - return jsonify({"Implements": ["NetworkDriver"]}) - - [email protected]('/NetworkDriver.GetCapabilities', methods=['POST']) -def get_capability(): - return jsonify({"Scope": "global"}) - - [email protected]('/NetworkDriver.DiscoverNew', methods=['POST']) -def new_discovery(): - return jsonify({}) - - [email protected]('/NetworkDriver.DiscoverDelete', methods=['POST']) -def delete_discovery(): - return jsonify({}) - - [email protected]('/NetworkDriver.CreateNetwork', methods=['POST']) -def create_network(): - if not request.data: - abort(400) - - data = json.loads(request.data) - - # NetworkID will have docker generated network uuid and it - # becomes 'name' in a OVN Logical switch record. - network = data.get("NetworkID", "") - if not network: - abort(400) - - # Limit subnet handling to ipv4 till ipv6 usecase is clear. - ipv4_data = data.get("IPv4Data", "") - if not ipv4_data: - error = "create_network: No ipv4 subnet provided" - return jsonify({'Err': error}) - - subnet = ipv4_data[0].get("Pool", "") - if not subnet: - error = "create_network: no subnet in ipv4 data from libnetwork" - return jsonify({'Err': error}) - - gateway_ip = ipv4_data[0].get("Gateway", "").rsplit('/', 1)[0] - if not gateway_ip: - error = "create_network: no gateway in ipv4 data from libnetwork" - return jsonify({'Err': error}) - - try: - ovn_nbctl("ls-add", network, "--", "set", "Logical_Switch", - network, "external_ids:subnet=" + subnet, - "external_ids:gateway_ip=" + gateway_ip) - except Exception as e: - error = "create_network: ls-add %s" % (str(e)) - return jsonify({'Err': error}) - - return jsonify({}) - - [email protected]('/NetworkDriver.DeleteNetwork', methods=['POST']) -def delete_network(): - if not request.data: - abort(400) - - data = json.loads(request.data) - - nid = data.get("NetworkID", "") - if not nid: - abort(400) - - try: - ovn_nbctl("ls-del", nid) - except Exception as e: - error = "delete_network: ls-del %s" % (str(e)) - return jsonify({'Err': error}) - - return jsonify({}) - - [email protected]('/NetworkDriver.CreateEndpoint', methods=['POST']) -def create_endpoint(): - if not request.data: - abort(400) - - data = json.loads(request.data) - - nid = data.get("NetworkID", "") - if not nid: - abort(400) - - eid = data.get("EndpointID", "") - if not eid: - abort(400) - - interface = data.get("Interface", "") - if not interface: - error = "create_endpoint: no interfaces structure supplied by " \ - "libnetwork" - return jsonify({'Err': error}) - - ip_address_and_mask = interface.get("Address", "") - if not ip_address_and_mask: - error = "create_endpoint: ip address not provided by libnetwork" - return jsonify({'Err': error}) - - ip_address = ip_address_and_mask.rsplit('/', 1)[0] - mac_address_input = interface.get("MacAddress", "") - mac_address_output = "" - - try: - ovn_nbctl("lsp-add", nid, eid) - except Exception as e: - error = "create_endpoint: lsp-add (%s)" % (str(e)) - return jsonify({'Err': error}) - - if not mac_address_input: - mac_address = "02:%02x:%02x:%02x:%02x:%02x" % (random.randint(0, 255), - random.randint(0, 255), - random.randint(0, 255), - random.randint(0, 255), - random.randint(0, 255)) - else: - mac_address = mac_address_input - - try: - ovn_nbctl("lsp-set-addresses", eid, - mac_address + " " + ip_address) - except Exception as e: - error = "create_endpoint: lsp-set-addresses (%s)" % (str(e)) - return jsonify({'Err': error}) - - # Only return a mac address if one did not come as request. - mac_address_output = "" - if not mac_address_input: - mac_address_output = mac_address - - return jsonify({"Interface": { - "Address": "", - "AddressIPv6": "", - "MacAddress": mac_address_output - }}) - - -def get_lsp_addresses(eid): - ret = ovn_nbctl("--if-exists", "get", "Logical_Switch_Port", eid, - "addresses") - if not ret: - error = "endpoint not found in OVN database" - return (None, None, error) - addresses = ast.literal_eval(ret) - if len(addresses) == 0: - error = "unexpected return while fetching addresses" - return (None, None, error) - (mac_address, ip_address) = addresses[0].split() - return (mac_address, ip_address, None) - - [email protected]('/NetworkDriver.EndpointOperInfo', methods=['POST']) -def show_endpoint(): - if not request.data: - abort(400) - - data = json.loads(request.data) - - nid = data.get("NetworkID", "") - if not nid: - abort(400) - - eid = data.get("EndpointID", "") - if not eid: - abort(400) - - try: - (mac_address, ip_address, error) = get_lsp_addresses(eid) - if error: - jsonify({'Err': error}) - except Exception as e: - error = "show_endpoint: get Logical_Switch_Port addresses. (%s)" \ - % (str(e)) - return jsonify({'Err': error}) - - veth_outside = eid[0:15] - return jsonify({"Value": {"ip_address": ip_address, - "mac_address": mac_address, - "veth_outside": veth_outside - }}) - - [email protected]('/NetworkDriver.DeleteEndpoint', methods=['POST']) -def delete_endpoint(): - if not request.data: - abort(400) - - data = json.loads(request.data) - - nid = data.get("NetworkID", "") - if not nid: - abort(400) - - eid = data.get("EndpointID", "") - if not eid: - abort(400) - - try: - ovn_nbctl("lsp-del", eid) - except Exception as e: - error = "delete_endpoint: lsp-del %s" % (str(e)) - return jsonify({'Err': error}) - - return jsonify({}) - - [email protected]('/NetworkDriver.Join', methods=['POST']) -def network_join(): - if not request.data: - abort(400) - - data = json.loads(request.data) - - nid = data.get("NetworkID", "") - if not nid: - abort(400) - - eid = data.get("EndpointID", "") - if not eid: - abort(400) - - sboxkey = data.get("SandboxKey", "") - if not sboxkey: - abort(400) - - # sboxkey is of the form: /var/run/docker/netns/CONTAINER_ID - vm_id = sboxkey.rsplit('/')[-1] - - try: - (mac_address, ip_address, error) = get_lsp_addresses(eid) - if error: - jsonify({'Err': error}) - except Exception as e: - error = "network_join: %s" % (str(e)) - return jsonify({'Err': error}) - - veth_outside = eid[0:15] - veth_inside = eid[0:13] + "_c" - command = "ip link add %s type veth peer name %s" \ - % (veth_inside, veth_outside) - try: - call_popen(shlex.split(command)) - except Exception as e: - error = "network_join: failed to create veth pair (%s)" % (str(e)) - return jsonify({'Err': error}) - - command = "ip link set dev %s address %s" \ - % (veth_inside, mac_address) - - try: - call_popen(shlex.split(command)) - except Exception as e: - error = "network_join: failed to set veth mac address (%s)" % (str(e)) - return jsonify({'Err': error}) - - command = "ip link set %s up" % (veth_outside) - - try: - call_popen(shlex.split(command)) - except Exception as e: - error = "network_join: failed to up the veth interface (%s)" % (str(e)) - return jsonify({'Err': error}) - - try: - ovs_vsctl("add-port", OVN_BRIDGE, veth_outside) - ovs_vsctl("set", "interface", veth_outside, - "external_ids:attached-mac=" + mac_address, - "external_ids:iface-id=" + eid, - "external_ids:vm-id=" + vm_id, - "external_ids:iface-status=active") - except Exception as e: - error = "network_join: failed to create a port (%s)" % (str(e)) - return jsonify({'Err': error}) - - return jsonify({"InterfaceName": { - "SrcName": veth_inside, - "DstPrefix": "eth" - }, - "Gateway": "", - "GatewayIPv6": ""}) - - [email protected]('/NetworkDriver.Leave', methods=['POST']) -def network_leave(): - if not request.data: - abort(400) - - data = json.loads(request.data) - - nid = data.get("NetworkID", "") - if not nid: - abort(400) - - eid = data.get("EndpointID", "") - if not eid: - abort(400) - - veth_outside = eid[0:15] - command = "ip link delete %s" % (veth_outside) - try: - call_popen(shlex.split(command)) - except Exception as e: - error = "network_leave: failed to delete veth pair (%s)" % (str(e)) - return jsonify({'Err': error}) - - try: - ovs_vsctl("--if-exists", "del-port", veth_outside) - except Exception as e: - error = "network_leave: failed to delete port (%s)" % (str(e)) - return jsonify({'Err': error}) - - return jsonify({}) - -if __name__ == '__main__': - prepare() - app.run(host='0.0.0.0') diff --git a/utilities/ovn-docker-underlay-driver.in b/utilities/ovn-docker-underlay-driver.in deleted file mode 100755 index 229418500..000000000 --- a/utilities/ovn-docker-underlay-driver.in +++ /dev/null @@ -1,677 +0,0 @@ -#! @PYTHON3@ -# Copyright (C) 2015 Nicira, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import argparse -import atexit -import getpass -import json -import os -import re -import shlex -import subprocess -import sys -import time -import uuid - -import ovs.dirs -import ovs.util -import ovs.daemon -import ovs.unixctl.server -import ovs.vlog - -from neutronclient.v2_0 import client -from flask import Flask, jsonify -from flask import request, abort - -app = Flask(__name__) -vlog = ovs.vlog.Vlog("ovn-docker-underlay-driver") - -AUTH_STRATEGY = "" -AUTH_URL = "" -ENDPOINT_URL = "" -OVN_BRIDGE = "" -PASSWORD = "" -PLUGIN_DIR = "/etc/docker/plugins" -PLUGIN_FILE = "/etc/docker/plugins/openvswitch.spec" -TENANT_ID = "" -USERNAME = "" -VIF_ID = "" - - -def call_popen(cmd): - child = subprocess.Popen(cmd, stdout=subprocess.PIPE) - output = child.communicate() - if child.returncode: - raise RuntimeError("Fatal error executing %s" % (cmd)) - if len(output) == 0 or output[0] == None: - output = "" - else: - output = output[0].strip() - return output - - -def call_prog(prog, args_list): - cmd = [prog, "--timeout=5", "-vconsole:off"] + args_list - return call_popen(cmd) - - -def ovs_vsctl(*args): - return call_prog("ovs-vsctl", list(args)) - - -def cleanup(): - if os.path.isfile(PLUGIN_FILE): - os.remove(PLUGIN_FILE) - - -def ovn_init_underlay(args): - global USERNAME, PASSWORD, TENANT_ID, AUTH_URL, AUTH_STRATEGY, VIF_ID - global OVN_BRIDGE - - if not args.bridge: - sys.exit("OVS bridge name not provided") - OVN_BRIDGE = args.bridge - - VIF_ID = os.environ.get('OS_VIF_ID', '') - if not VIF_ID: - sys.exit("env OS_VIF_ID not set") - USERNAME = os.environ.get('OS_USERNAME', '') - if not USERNAME: - sys.exit("env OS_USERNAME not set") - TENANT_ID = os.environ.get('OS_TENANT_ID', '') - if not TENANT_ID: - sys.exit("env OS_TENANT_ID not set") - AUTH_URL = os.environ.get('OS_AUTH_URL', '') - if not AUTH_URL: - sys.exit("env OS_AUTH_URL not set") - AUTH_STRATEGY = "keystone" - - PASSWORD = os.environ.get('OS_PASSWORD', '') - if not PASSWORD: - PASSWORD = getpass.getpass() - - -def prepare(): - parser = argparse.ArgumentParser() - parser.add_argument('--bridge', help="The Bridge to which containers " - "interfaces connect to.") - - ovs.vlog.add_args(parser) - ovs.daemon.add_args(parser) - args = parser.parse_args() - ovs.vlog.handle_args(args) - ovs.daemon.handle_args(args) - ovn_init_underlay(args) - - if not os.path.isdir(PLUGIN_DIR): - os.makedirs(PLUGIN_DIR) - - ovs.daemon.daemonize() - try: - fo = open(PLUGIN_FILE, "w") - fo.write("tcp://127.0.0.1:5000") - fo.close() - except Exception as e: - ovs.util.ovs_fatal(0, "Failed to write to spec file (%s)" % str(e), - vlog) - - atexit.register(cleanup) - - [email protected]('/Plugin.Activate', methods=['POST']) -def plugin_activate(): - return jsonify({"Implements": ["NetworkDriver"]}) - - [email protected]('/NetworkDriver.GetCapabilities', methods=['POST']) -def get_capability(): - return jsonify({"Scope": "global"}) - - [email protected]('/NetworkDriver.DiscoverNew', methods=['POST']) -def new_discovery(): - return jsonify({}) - - [email protected]('/NetworkDriver.DiscoverDelete', methods=['POST']) -def delete_discovery(): - return jsonify({}) - - -def neutron_login(): - try: - neutron = client.Client(username=USERNAME, - password=PASSWORD, - tenant_id=TENANT_ID, - auth_url=AUTH_URL, - endpoint_url=ENDPOINT_URL, - auth_strategy=AUTH_STRATEGY) - except Exception as e: - raise RuntimeError("Failed to login into Neutron(%s)" % str(e)) - return neutron - - -def get_networkuuid_by_name(neutron, name): - param = {'fields': 'id', 'name': name} - ret = neutron.list_networks(**param) - if len(ret['networks']) > 1: - raise RuntimeError("More than one network for the given name") - elif len(ret['networks']) == 0: - network = None - else: - network = ret['networks'][0]['id'] - return network - - -def get_subnetuuid_by_name(neutron, name): - param = {'fields': 'id', 'name': name} - ret = neutron.list_subnets(**param) - if len(ret['subnets']) > 1: - raise RuntimeError("More than one subnet for the given name") - elif len(ret['subnets']) == 0: - subnet = None - else: - subnet = ret['subnets'][0]['id'] - return subnet - - [email protected]('/NetworkDriver.CreateNetwork', methods=['POST']) -def create_network(): - if not request.data: - abort(400) - - data = json.loads(request.data) - - # NetworkID will have docker generated network uuid and it - # becomes 'name' in a neutron network record. - network = data.get("NetworkID", "") - if not network: - abort(400) - - # Limit subnet handling to ipv4 till ipv6 usecase is clear. - ipv4_data = data.get("IPv4Data", "") - if not ipv4_data: - error = "create_network: No ipv4 subnet provided" - return jsonify({'Err': error}) - - subnet = ipv4_data[0].get("Pool", "") - if not subnet: - error = "create_network: no subnet in ipv4 data from libnetwork" - return jsonify({'Err': error}) - - gateway_ip = ipv4_data[0].get("Gateway", "").rsplit('/', 1)[0] - if not gateway_ip: - error = "create_network: no gateway in ipv4 data from libnetwork" - return jsonify({'Err': error}) - - try: - neutron = neutron_login() - except Exception as e: - error = "create_network: neutron login. (%s)" % (str(e)) - return jsonify({'Err': error}) - - try: - if get_networkuuid_by_name(neutron, network): - error = "create_network: network has already been created" - return jsonify({'Err': error}) - except Exception as e: - error = "create_network: neutron network uuid by name. (%s)" % (str(e)) - return jsonify({'Err': error}) - - try: - body = {'network': {'name': network, 'admin_state_up': True}} - ret = neutron.create_network(body) - network_id = ret['network']['id'] - except Exception as e: - error = "create_network: neutron net-create call. (%s)" % str(e) - return jsonify({'Err': error}) - - subnet_name = "docker-%s" % (network) - - try: - body = {'subnet': {'network_id': network_id, - 'ip_version': 4, - 'cidr': subnet, - 'gateway_ip': gateway_ip, - 'name': subnet_name}} - created_subnet = neutron.create_subnet(body) - except Exception as e: - error = "create_network: neutron subnet-create call. (%s)" % str(e) - return jsonify({'Err': error}) - - return jsonify({}) - - [email protected]('/NetworkDriver.DeleteNetwork', methods=['POST']) -def delete_network(): - if not request.data: - abort(400) - - data = json.loads(request.data) - - nid = data.get("NetworkID", "") - if not nid: - abort(400) - - try: - neutron = neutron_login() - except Exception as e: - error = "delete_network: neutron login. (%s)" % (str(e)) - return jsonify({'Err': error}) - - try: - network = get_networkuuid_by_name(neutron, nid) - if not network: - error = "delete_network: failed in network by name. (%s)" % (nid) - return jsonify({'Err': error}) - except Exception as e: - error = "delete_network: network uuid by name. (%s)" % (str(e)) - return jsonify({'Err': error}) - - try: - neutron.delete_network(network) - except Exception as e: - error = "delete_network: neutron net-delete. (%s)" % str(e) - return jsonify({'Err': error}) - - return jsonify({}) - - -def reserve_vlan(): - reserved_vlan = 0 - vlans = ovs_vsctl("--if-exists", "get", "Open_vSwitch", ".", - "external_ids:vlans").strip('"') - if not vlans: - reserved_vlan = 1 - ovs_vsctl("set", "Open_vSwitch", ".", - "external_ids:vlans=" + str(reserved_vlan)) - return reserved_vlan - - vlan_set = str(vlans).split(',') - - for vlan in range(1, 4095): - if str(vlan) not in vlan_set: - vlan_set.append(str(vlan)) - reserved_vlan = vlan - vlans = re.sub(r'[ \[\]\']', '', str(vlan_set)) - ovs_vsctl("set", "Open_vSwitch", ".", - "external_ids:vlans=" + vlans) - return reserved_vlan - - if not reserved_vlan: - raise RuntimeError("No more vlans available on this host") - - -def unreserve_vlan(reserved_vlan): - vlans = ovs_vsctl("--if-exists", "get", "Open_vSwitch", ".", - "external_ids:vlans").strip('"') - if not vlans: - return - - vlan_set = str(vlans).split(',') - if str(reserved_vlan) not in vlan_set: - return - - vlan_set.remove(str(reserved_vlan)) - vlans = re.sub(r'[ \[\]\']', '', str(vlan_set)) - if vlans: - ovs_vsctl("set", "Open_vSwitch", ".", "external_ids:vlans=" + vlans) - else: - ovs_vsctl("remove", "Open_vSwitch", ".", "external_ids", "vlans") - - -def create_port_underlay(neutron, network, eid, ip_address, mac_address): - reserved_vlan = reserve_vlan() - if mac_address: - body = {'port': {'network_id': network, - 'binding:profile': {'parent_name': VIF_ID, - 'tag': int(reserved_vlan)}, - 'mac_address': mac_address, - 'fixed_ips': [{'ip_address': ip_address}], - 'name': eid, - 'admin_state_up': True}} - else: - body = {'port': {'network_id': network, - 'binding:profile': {'parent_name': VIF_ID, - 'tag': int(reserved_vlan)}, - 'fixed_ips': [{'ip_address': ip_address}], - 'name': eid, - 'admin_state_up': True}} - - try: - ret = neutron.create_port(body) - mac_address = ret['port']['mac_address'] - except Exception as e: - unreserve_vlan(reserved_vlan) - raise RuntimeError("Failed in creation of neutron port (%s)." % str(e)) - - ovs_vsctl("set", "Open_vSwitch", ".", - "external_ids:" + eid + "_vlan=" + str(reserved_vlan)) - - return mac_address - - -def get_endpointuuid_by_name(neutron, name): - param = {'fields': 'id', 'name': name} - ret = neutron.list_ports(**param) - if len(ret['ports']) > 1: - raise RuntimeError("More than one endpoint for the given name") - elif len(ret['ports']) == 0: - endpoint = None - else: - endpoint = ret['ports'][0]['id'] - return endpoint - - [email protected]('/NetworkDriver.CreateEndpoint', methods=['POST']) -def create_endpoint(): - if not request.data: - abort(400) - - data = json.loads(request.data) - - nid = data.get("NetworkID", "") - if not nid: - abort(400) - - eid = data.get("EndpointID", "") - if not eid: - abort(400) - - interface = data.get("Interface", "") - if not interface: - error = "create_endpoint: no interfaces supplied by libnetwork" - return jsonify({'Err': error}) - - ip_address_and_mask = interface.get("Address", "") - if not ip_address_and_mask: - error = "create_endpoint: ip address not provided by libnetwork" - return jsonify({'Err': error}) - - ip_address = ip_address_and_mask.rsplit('/', 1)[0] - mac_address_input = interface.get("MacAddress", "") - mac_address_output = "" - - try: - neutron = neutron_login() - except Exception as e: - error = "create_endpoint: neutron login. (%s)" % (str(e)) - return jsonify({'Err': error}) - - try: - endpoint = get_endpointuuid_by_name(neutron, eid) - if endpoint: - error = "create_endpoint: Endpoint has already been created" - return jsonify({'Err': error}) - except Exception as e: - error = "create_endpoint: endpoint uuid by name. (%s)" % (str(e)) - return jsonify({'Err': error}) - - try: - network = get_networkuuid_by_name(neutron, nid) - if not network: - error = "Failed to get neutron network record for (%s)" % (nid) - return jsonify({'Err': error}) - except Exception as e: - error = "create_endpoint: network uuid by name. (%s)" % (str(e)) - return jsonify({'Err': error}) - - try: - mac_address = create_port_underlay(neutron, network, eid, ip_address, - mac_address_input) - except Exception as e: - error = "create_endpoint: neutron port-create (%s)" % (str(e)) - return jsonify({'Err': error}) - - if not mac_address_input: - mac_address_output = mac_address - - return jsonify({"Interface": { - "Address": "", - "AddressIPv6": "", - "MacAddress": mac_address_output - }}) - - [email protected]('/NetworkDriver.EndpointOperInfo', methods=['POST']) -def show_endpoint(): - if not request.data: - abort(400) - - data = json.loads(request.data) - - nid = data.get("NetworkID", "") - if not nid: - abort(400) - - eid = data.get("EndpointID", "") - if not eid: - abort(400) - - try: - neutron = neutron_login() - except Exception as e: - error = "%s" % (str(e)) - return jsonify({'Err': error}) - - try: - endpoint = get_endpointuuid_by_name(neutron, eid) - if not endpoint: - error = "show_endpoint: Failed to get endpoint by name" - return jsonify({'Err': error}) - except Exception as e: - error = "show_endpoint: get endpoint by name. (%s)" % (str(e)) - return jsonify({'Err': error}) - - try: - ret = neutron.show_port(endpoint) - mac_address = ret['port']['mac_address'] - ip_address = ret['port']['fixed_ips'][0]['ip_address'] - except Exception as e: - error = "show_endpoint: show port (%s)" % (str(e)) - return jsonify({'Err': error}) - - veth_outside = eid[0:15] - return jsonify({"Value": {"ip_address": ip_address, - "mac_address": mac_address, - "veth_outside": veth_outside - }}) - - [email protected]('/NetworkDriver.DeleteEndpoint', methods=['POST']) -def delete_endpoint(): - if not request.data: - abort(400) - - data = json.loads(request.data) - - nid = data.get("NetworkID", "") - if not nid: - abort(400) - - eid = data.get("EndpointID", "") - if not eid: - abort(400) - - try: - neutron = neutron_login() - except Exception as e: - error = "delete_endpoint: neutron login (%s)" % (str(e)) - return jsonify({'Err': error}) - - endpoint = get_endpointuuid_by_name(neutron, eid) - if not endpoint: - return jsonify({}) - - reserved_vlan = ovs_vsctl("--if-exists", "get", "Open_vSwitch", ".", - "external_ids:" + eid + "_vlan").strip('"') - if reserved_vlan: - unreserve_vlan(reserved_vlan) - ovs_vsctl("remove", "Open_vSwitch", ".", "external_ids", - eid + "_vlan") - - try: - neutron.delete_port(endpoint) - except Exception as e: - error = "delete_endpoint: neutron port-delete. (%s)" % (str(e)) - return jsonify({'Err': error}) - - return jsonify({}) - - [email protected]('/NetworkDriver.Join', methods=['POST']) -def network_join(): - if not request.data: - abort(400) - - data = json.loads(request.data) - - nid = data.get("NetworkID", "") - if not nid: - abort(400) - - eid = data.get("EndpointID", "") - if not eid: - abort(400) - - sboxkey = data.get("SandboxKey", "") - if not sboxkey: - abort(400) - - # sboxkey is of the form: /var/run/docker/netns/CONTAINER_ID - vm_id = sboxkey.rsplit('/')[-1] - - try: - neutron = neutron_login() - except Exception as e: - error = "network_join: neutron login. (%s)" % (str(e)) - return jsonify({'Err': error}) - - subnet_name = "docker-%s" % (nid) - try: - subnet = get_subnetuuid_by_name(neutron, subnet_name) - if not subnet: - error = "network_join: can't find subnet in neutron" - return jsonify({'Err': error}) - except Exception as e: - error = "network_join: subnet uuid by name. (%s)" % (str(e)) - return jsonify({'Err': error}) - - try: - ret = neutron.show_subnet(subnet) - gateway_ip = ret['subnet']['gateway_ip'] - if not gateway_ip: - error = "network_join: no gateway_ip for the subnet" - return jsonify({'Err': error}) - except Exception as e: - error = "network_join: neutron show subnet. (%s)" % (str(e)) - return jsonify({'Err': error}) - - try: - endpoint = get_endpointuuid_by_name(neutron, eid) - if not endpoint: - error = "network_join: Failed to get endpoint by name" - return jsonify({'Err': error}) - except Exception as e: - error = "network_join: neutron endpoint by name. (%s)" % (str(e)) - return jsonify({'Err': error}) - - try: - ret = neutron.show_port(endpoint) - mac_address = ret['port']['mac_address'] - except Exception as e: - error = "network_join: neutron show port. (%s)" % (str(e)) - return jsonify({'Err': error}) - - veth_outside = eid[0:15] - veth_inside = eid[0:13] + "_c" - command = "ip link add %s type veth peer name %s" \ - % (veth_inside, veth_outside) - try: - call_popen(shlex.split(command)) - except Exception as e: - error = "network_join: failed to create veth pair. (%s)" % (str(e)) - return jsonify({'Err': error}) - - command = "ip link set dev %s address %s" \ - % (veth_inside, mac_address) - - try: - call_popen(shlex.split(command)) - except Exception as e: - error = "network_join: failed to set veth mac address. (%s)" % (str(e)) - return jsonify({'Err': error}) - - command = "ip link set %s up" % (veth_outside) - - try: - call_popen(shlex.split(command)) - except Exception as e: - error = "network_join: failed to up the veth iface. (%s)" % (str(e)) - return jsonify({'Err': error}) - - try: - reserved_vlan = ovs_vsctl("--if-exists", "get", "Open_vSwitch", ".", - "external_ids:" + eid + "_vlan").strip('"') - if not reserved_vlan: - error = "network_join: no reserved vlan for this endpoint" - return jsonify({'Err': error}) - ovs_vsctl("add-port", OVN_BRIDGE, veth_outside, "tag=" + reserved_vlan) - except Exception as e: - error = "network_join: failed to create a OVS port. (%s)" % (str(e)) - return jsonify({'Err': error}) - - return jsonify({"InterfaceName": { - "SrcName": veth_inside, - "DstPrefix": "eth" - }, - "Gateway": gateway_ip, - "GatewayIPv6": ""}) - - [email protected]('/NetworkDriver.Leave', methods=['POST']) -def network_leave(): - if not request.data: - abort(400) - - data = json.loads(request.data) - - nid = data.get("NetworkID", "") - if not nid: - abort(400) - - eid = data.get("EndpointID", "") - if not eid: - abort(400) - - veth_outside = eid[0:15] - command = "ip link delete %s" % (veth_outside) - try: - call_popen(shlex.split(command)) - except Exception as e: - error = "network_leave: failed to delete veth pair. (%s)" % (str(e)) - return jsonify({'Err': error}) - - try: - ovs_vsctl("--if-exists", "del-port", veth_outside) - except Exception as e: - error = "network_leave: Failed to delete port (%s)" % (str(e)) - return jsonify({'Err': error}) - - return jsonify({}) - -if __name__ == '__main__': - prepare() - app.run(host='127.0.0.1') -- 2.55.0 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
