Merge branch 'py3' features 8029 8030

Change-Id: Ia670d01fc45d63f4051209ef73ca272054895873
Signed-off-by: tierno <alfonso.tiernosepulveda@telefonica.com>
diff --git a/Dockerfile b/Dockerfile
index a0f45ba..8eec007 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -18,30 +18,36 @@
 # Use docker/Dockerfile-local for running osm/RO in a docker container from source
 
 FROM ubuntu:16.04
-
 RUN  apt-get update && \
-  DEBIAN_FRONTEND=noninteractive apt-get -y install git make python python-pip debhelper python3 python3-all python3-pip python3-setuptools && \
-  DEBIAN_FRONTEND=noninteractive apt-get -y install wget tox apt-utils flake8 python-nose python-mock && \
-  DEBIAN_FRONTEND=noninteractive pip install pip==9.0.3 && \
-  DEBIAN_FRONTEND=noninteractive pip3 install pip==9.0.3 && \
-  DEBIAN_FRONTEND=noninteractive pip install -U setuptools setuptools-version-command stdeb && \
-  DEBIAN_FRONTEND=noninteractive pip install -U pyang pyangbind && \
-  DEBIAN_FRONTEND=noninteractive pip3 install -U pyang pyangbind && \
-  DEBIAN_FRONTEND=noninteractive apt-get -y install python-yaml python-netaddr python-boto && \
-  DEBIAN_FRONTEND=noninteractive apt-get -y install software-properties-common && \
-  DEBIAN_FRONTEND=noninteractive add-apt-repository -y cloud-archive:queens && \
-  DEBIAN_FRONTEND=noninteractive apt-get update && \
-  DEBIAN_FRONTEND=noninteractive apt-get -y install python-novaclient python-keystoneclient python-glanceclient python-cinderclient python-neutronclient python-networking-l2gw && \
-  DEBIAN_FRONTEND=noninteractive pip install -U progressbar pyvmomi pyvcloud==19.1.1 && \
-  DEBIAN_FRONTEND=noninteractive pip install -U fog05rest && \
-  DEBIAN_FRONTEND=noninteractive pip install -U azure && \
-  DEBIAN_FRONTEND=noninteractive apt-get -y install python-argcomplete python-bottle python-cffi python-packaging python-paramiko python-pkgconfig libmysqlclient-dev libssl-dev libffi-dev python-mysqldb && \
-  DEBIAN_FRONTEND=noninteractive apt-get -y install python-logutils python-openstackclient python-openstacksdk && \
-  DEBIAN_FRONTEND=noninteractive pip install untangle && \
-  DEBIAN_FRONTEND=noninteractive pip install pyone && \
-  DEBIAN_FRONTEND=noninteractive pip install -e git+https://github.com/python-oca/python-oca#egg=oca
+  DEBIAN_FRONTEND=noninteractive apt-get --yes install git tox make python-all python3 python3-pip debhelper wget && \
+  DEBIAN_FRONTEND=noninteractive apt-get --yes install python3-all libssl-dev flake8 && \
+  DEBIAN_FRONTEND=noninteractive pip3 install -U setuptools setuptools-version-command stdeb
 
+# FROM ubuntu:16.04
 
+# RUN  apt-get update && \
+#   DEBIAN_FRONTEND=noninteractive apt-get -y install git make python python-pip debhelper python3 python3-all python3-pip python3-setuptools && \
+#   DEBIAN_FRONTEND=noninteractive apt-get -y install wget tox apt-utils flake8 python-nose python-mock && \
+#   DEBIAN_FRONTEND=noninteractive pip install pip==9.0.3 && \
+#   DEBIAN_FRONTEND=noninteractive pip3 install pip==9.0.3 && \
+#   DEBIAN_FRONTEND=noninteractive pip install -U setuptools setuptools-version-command stdeb && \
+#   DEBIAN_FRONTEND=noninteractive pip install -U pyang pyangbind && \
+#   DEBIAN_FRONTEND=noninteractive pip3 install -U pyang pyangbind && \
+#   DEBIAN_FRONTEND=noninteractive apt-get -y install python-yaml python-netaddr python-boto && \
+#   DEBIAN_FRONTEND=noninteractive apt-get -y install software-properties-common && \
+#   DEBIAN_FRONTEND=noninteractive add-apt-repository -y cloud-archive:queens && \
+#   DEBIAN_FRONTEND=noninteractive apt-get update && \
+#   DEBIAN_FRONTEND=noninteractive apt-get -y install python-novaclient python-keystoneclient python-glanceclient python-cinderclient python-neutronclient python-networking-l2gw && \
+#   DEBIAN_FRONTEND=noninteractive pip install -U progressbar pyvmomi pyvcloud==19.1.1 && \
+#   DEBIAN_FRONTEND=noninteractive pip install -U fog05rest && \
+#   DEBIAN_FRONTEND=noninteractive pip install -U azure && \
+#   DEBIAN_FRONTEND=noninteractive apt-get -y install python-argcomplete python-bottle python-cffi python-packaging python-paramiko python-pkgconfig libmysqlclient-dev libssl-dev libffi-dev python-mysqldb && \
+#   DEBIAN_FRONTEND=noninteractive apt-get -y install python-logutils python-openstackclient python-openstacksdk && \
+#   DEBIAN_FRONTEND=noninteractive pip install untangle && \
+#   DEBIAN_FRONTEND=noninteractive pip install pyone && \
+#   DEBIAN_FRONTEND=noninteractive pip install -e git+https://github.com/python-oca/python-oca#egg=oca
+
+# TODO py3 comment
 # Uncomment this block to generate automatically a debian package and show info
 # # Set the working directory to /app
 # WORKDIR /app
diff --git a/Dockerfile-local b/Dockerfile-local
new file mode 100644
index 0000000..8430fa9
--- /dev/null
+++ b/Dockerfile-local
@@ -0,0 +1,100 @@
+##
+# 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.
+##
+
+FROM ubuntu:18.04
+
+LABEL authors="Alfonso Tierno"
+
+RUN apt-get update && apt-get install -y git python3 python3-pip \
+    && python3 -m pip install --upgrade pip \
+    && DEBIAN_FRONTEND=noninteractive apt-get -y install libmysqlclient-dev mysql-client \
+    && DEBIAN_FRONTEND=noninteractive python3 -m pip install -U networking-l2gw  \
+    && DEBIAN_FRONTEND=noninteractive python3 -m pip install -U progressbar pyvmomi pyvcloud==19.1.1  \
+    && DEBIAN_FRONTEND=noninteractive apt-get -y install genisoimage
+
+# This is not needed, because package dependency will install anyway.
+# But done here in order to harry up image generation using cache
+RUN DEBIAN_FRONTEND=noninteractive  apt-get -y install python3-neutronclient python3-openstackclient \
+    python3-requests python3-netaddr python3-argcomplete
+
+#    DEBIAN_FRONTEND=noninteractive apt-get -y install python-openstacksdk python-openstackclient && \
+# TODO py3   DEBIAN_FRONTEND=noninteractive add-apt-repository -y cloud-archive:rocky && apt-get update && apt-get install -y python3-networking-l2gw \
+
+#    DEBIAN_FRONTEND=noninteractive apt-get -y install python-cffi  libssl-dev libffi-dev python-mysqldb && \
+#    DEBIAN_FRONTEND=noninteractive pip2 install -U azure && \
+#    DEBIAN_FRONTEND=noninteractive pip2 install -U fog05rest && \
+#    && DEBIAN_FRONTEND=noninteractive apt-get -y install software-properties-common && \
+#    DEBIAN_FRONTEND=noninteractive apt-get -y install wget tox && \
+#    DEBIAN_FRONTEND=noninteractive pip2 install untangle && \
+#    DEBIAN_FRONTEND=noninteractive pip2 install pyone && \
+#    DEBIAN_FRONTEND=noninteractive pip2 install -e git+https://github.com/python-oca/python-oca#egg=oca && \
+
+COPY . /root/RO
+
+RUN /root/RO/RO/osm_ro/scripts/install-osm-im.sh --develop && \
+    /root/RO/RO/osm_ro/scripts/install-lib-osm-openvim.sh --develop && \
+    mkdir -p /var/log/osm && \
+    python3 -m pip install -e /root/RO/RO && \
+    python3 -m pip install -e /root/RO/RO-client && \
+    python3 -m pip install -e /root/RO/RO-VIM-vmware && \
+    python3 -m pip install -e /root/RO/RO-VIM-openstack && \
+    python3 -m pip install -e /root/RO/RO-VIM-openvim && \
+    python3 -m pip install -e /root/RO/RO-VIM-aws && \
+    python3 -m pip install -e /root/RO/RO-VIM-fos && \
+    python3 -m pip install -e /root/RO/RO-SDN-dynpac && \
+    python3 -m pip install -e /root/RO/RO-SDN-tapi && \
+    rm -rf /root/.cache && \
+    apt-get clean && \
+    rm -rf /var/lib/apt/lists/*
+
+VOLUME /var/log/osm
+
+EXPOSE 9090
+
+# Two mysql databases are needed (DB and DB_OVIM). Can be hosted on same or separated containers
+# These ENV must be provided
+# RO_DB_HOST: host of the main
+# RO_DB_OVIM_HOST: ...        if empty RO_DB_HOST is assumed
+# RO_DB_ROOT_PASSWORD: this has to be provided first time for creating database. It will create and init only if empty!
+# RO_DB_OVIM_ROOT_PASSWORD: ...  if empty RO_DB_ROOT_PASSWORD is assumed
+# RO_DB_USER:    default value 'mano'
+# RO_DB_OVIM_USER:       default value 'mano'
+# RO_DB_PASSWORD:        default value 'manopw'
+# RO_DB_OVIM_PASSWORD:        default value 'manopw'
+# RO_DB_PORT:             default value '3306'
+# RO_DB_OVIM_PORT:        default value '3306'
+# RO_DB_NAME:             default value 'mano_db'
+# RO_DB_OVIM_NAME:        default value 'mano_vim_db'
+# RO_LOG_FILE:            default log to stderr if not defined
+
+ENV RO_DB_HOST="" \
+    RO_DB_OVIM_HOST="" \
+    RO_DB_ROOT_PASSWORD="" \
+    RO_DB_OVIM_ROOT_PASSWORD="" \
+    RO_DB_USER=mano \
+    RO_DB_OVIM_USER=mano \
+    RO_DB_PASSWORD=manopw \
+    RO_DB_OVIM_PASSWORD=manopw \
+    RO_DB_PORT=3306 \
+    RO_DB_OVIM_PORT=3306 \
+    RO_DB_NAME=mano_db \
+    RO_DB_OVIM_NAME=mano_vim_db \
+    OPENMANO_TENANT=osm \
+    RO_LOG_LEVEL=DEBUG
+
+CMD RO-start.sh
+
+# HEALTHCHECK --start-period=30s --interval=10s --timeout=5s --retries=12 \
+#  CMD curl --silent --fail localhost:9090/openmano/tenants || exit 1
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index 483b709..0000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,7 +0,0 @@
-#include MANIFEST.in
-#include requirements.txt
-include README.rst
-include openmano
-include openmanod
-recursive-include osm_ro *
-
diff --git a/Makefile b/Makefile
index 33deb4e..90ee12c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,3 @@
-# Copyright 2018 Telefonica S.A.
-#
 # 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
@@ -13,110 +11,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-.PHONY: all test clean
+SUBDIRS := $(wildcard */Makefile)
 
-SHELL := /bin/bash
+all: clean package
+clean: $(SUBDIRS)
+package: $(SUBDIRS)
 
-BRANCH ?= master
+$(SUBDIRS):
+	$(MAKE) -C $(@:Makefile=) $(MAKECMDGOALS)
 
-all:  #  lib-openvim    # osm-im
-	$(MAKE) clean_build build
-	$(MAKE) clean_build package
-
-clean: clean_build
-	rm -rf .build openvim IM
-
-clean_build:
-	rm -rf build
-	find osm_ro -name '*.pyc' -delete
-	find osm_ro -name '*.pyo' -delete
-
-prepare:
-#	ip install --user --upgrade setuptools
-	mkdir -p build/
-#	VER1=$(shell git describe | sed -e 's/^v//' |cut -d- -f1); \
-#	VER2=$(shell git describe | cut -d- -f2); \
-#	VER3=$(shell git describe | cut -d- -f3); \
-#	echo "$$VER1.dev$$VER2+$$VER3" > build/RO_VERSION
-	cp tox.ini build/
-	cp MANIFEST.in build/
-	cp requirements.txt build/
-	cp README.rst build/
-	cp setup.py build/
-	cp stdeb.cfg build/
-	cp -r osm_ro build/
-	cp openmano build/
-	cp openmanod build/
-	cp -r vnfs build/osm_ro
-	cp -r scenarios build/osm_ro
-	cp -r instance-scenarios build/osm_ro
-	cp -r scripts build/osm_ro
-	cp -r database_utils build/osm_ro
-	cp LICENSE build/osm_ro
-
-connectors: prepare
-	# python-novaclient is required for that
-	rm -f build/osm_ro/openmanolinkervimconn.py
-	cd build/osm_ro; for i in `ls vimconn_*.py |sed "s/\.py//"` ; do echo "import $$i" >> openmanolinkervimconn.py; done
-	python build/osm_ro/openmanolinkervimconn.py 2>&1
-	rm -f build/osm_ro/openmanolinkervimconn.py
-
-build: connectors prepare
-	python -m py_compile build/osm_ro/*.py
-#	cd build && tox -e flake8
-
-lib-openvim:
-	$(shell git clone https://osm.etsi.org/gerrit/osm/openvim)
-	LIB_BRANCH=$(shell git -C openvim branch -a|grep -oP 'remotes/origin/\K$(BRANCH)'); \
-	[ -z "$$LIB_BRANCH" ] && LIB_BRANCH='master'; \
-	echo "BRANCH: $(BRANCH)"; \
-	echo "LIB_OPENVIM_BRANCH: $$LIB_BRANCH"; \
-	git -C openvim checkout $$LIB_BRANCH
-	make -C openvim clean lite
-
-osm-im:
-	$(shell git clone https://osm.etsi.org/gerrit/osm/IM)
-	make -C IM clean all
-
-package: prepare
-#	apt-get install -y python-stdeb
-	cd build && python setup.py --command-packages=stdeb.command sdist_dsc --with-python2=True
-	cd build && cp osm_ro/scripts/python-osm-ro.postinst deb_dist/osm-ro*/debian/
-	cd build/deb_dist/osm-ro* && dpkg-buildpackage -rfakeroot -uc -us
-	mkdir -p .build
-	cp build/deb_dist/python-*.deb .build/
-
-snap:
-	echo "Nothing to be done yet"
-
-install: lib-openvim osm-im
-	dpkg -i IM/deb_dist/python-osm-im*.deb
-	dpkg -i openvim/.build/python-lib-osm-openvim*.deb
-	dpkg -i .build/python-osm-ro*.deb
-	cd .. && \
-	OSMLIBOVIM_PATH=`python -c 'import lib_osm_openvim; print lib_osm_openvim.__path__[0]'` || FATAL "lib-osm-openvim was not properly installed" && \
-	OSMRO_PATH=`python -c 'import osm_ro; print osm_ro.__path__[0]'` || FATAL "osm-ro was not properly installed" && \
-	USER=root DEBIAN_FRONTEND=noninteractive $$OSMRO_PATH/database_utils/install-db-server.sh --updatedb || FATAL "osm-ro db installation failed" && \
-	USER=root DEBIAN_FRONTEND=noninteractive $$OSMLIBOVIM_PATH/database_utils/install-db-server.sh -u mano -p manopw -d mano_vim_db --updatedb || FATAL "lib-osm-openvim db installation failed"
-	service osm-ro restart
-
-develop: prepare
-#	pip install -r requirements.txt
-	cd build && ./setup.py develop
-
-test:
-	. ./test/basictest.sh -f --insert-bashrc --install-openvim --init-openvim
-	. ./test/basictest.sh -f reset add-openvim
-	./test/test_RO.py deploy -n mgmt -t osm -i cirros034 -d local-openvim --timeout=30 --failfast
-	./test/test_RO.py vim  -t osm  -d local-openvim --timeout=30 --failfast
-
-build-docker-from-source:
-	docker build -t osm/openmano -f docker/Dockerfile-local .
-
-run-docker:
-	docker-compose -f docker/openmano-compose.yml up
-
-stop-docker:
-	docker-compose -f docker/openmano-compose.yml down
-
+.PHONY: all $(SUBDIRS)
 
diff --git a/README.rst b/README.rst
deleted file mode 100644
index 3a2be88..0000000
--- a/README.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-===========
-osm-ro
-===========
-
-osm-ro is the Resource Orchestrator for OSM, dealing with resource operations
-against different VIMs such as Openstack, VMware's vCloud Director, openvim
-and AWS.
-
diff --git a/RO-SDN-dynpac/Makefile b/RO-SDN-dynpac/Makefile
new file mode 100644
index 0000000..9fb4408
--- /dev/null
+++ b/RO-SDN-dynpac/Makefile
@@ -0,0 +1,24 @@
+##
+# 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.
+##
+
+all: clean package
+
+clean:
+	rm -rf dist deb_dist osm_rosdn_dynpac-*.tar.gz osm_rosdn_dynpac.egg-info .eggs
+
+package:
+	python3 setup.py --command-packages=stdeb.command sdist_dsc
+	cd deb_dist/osm-rosdn-dynpac*/ && dpkg-buildpackage -rfakeroot -uc -us
+
diff --git a/osm_ro/wim/wimconn_dynpac.py b/RO-SDN-dynpac/osm_rosdn_dynpac/wimconn_dynpac.py
similarity index 84%
rename from osm_ro/wim/wimconn_dynpac.py
rename to RO-SDN-dynpac/osm_rosdn_dynpac/wimconn_dynpac.py
index cc9376b..b32856b 100644
--- a/osm_ro/wim/wimconn_dynpac.py
+++ b/RO-SDN-dynpac/osm_rosdn_dynpac/wimconn_dynpac.py
@@ -26,10 +26,10 @@
 import logging
 from enum import Enum
 
-from wimconn import WimConnector, WimConnectorError
+from osm_ro.wim.sdnconn import SdnConnectorBase, SdnConnectorError
 
 
-class WimError(Enum):
+class SdnError(Enum):
     UNREACHABLE = 'Unable to reach the WIM.',
     SERVICE_TYPE_ERROR = 'Unexpected service_type. Only "L2" is accepted.',
     CONNECTION_POINTS_SIZE = \
@@ -47,7 +47,7 @@
     UNAUTHORIZED = "Failed while authenticating"
 
 
-class WimAPIActions(Enum):
+class SdnAPIActions(Enum):
     CHECK_CONNECTIVITY = "CHECK_CONNECTIVITY",
     CREATE_SERVICE = "CREATE_SERVICE",
     DELETE_SERVICE = "DELETE_SERVICE",
@@ -55,36 +55,34 @@
     SERVICE_STATUS = "SERVICE_STATUS",
 
 
-class DynpacConnector(WimConnector):
+class DynpacConnector(SdnConnectorBase):
     __supported_service_types = ["ELINE (L2)", "ELINE"]
     __supported_encapsulation_types = ["dot1q"]
-    __WIM_LOGGER = 'openmano.wimconn.dynpac'
+    __WIM_LOGGER = 'openmano.sdnconn.dynpac'
     __ENCAPSULATION_TYPE_PARAM = "service_endpoint_encapsulation_type"
     __ENCAPSULATION_INFO_PARAM = "service_endpoint_encapsulation_info"
     __BACKUP_PARAM = "backup"
     __BANDWIDTH_PARAM = "bandwidth"
     __SERVICE_ENDPOINT_PARAM = "service_endpoint_id"
-    __WAN_SERVICE_ENDPOINT_PARAM = "wan_service_endpoint_id"
-    __WAN_MAPPING_INFO_PARAM = "wan_service_mapping_info"
-    __SW_ID_PARAM = "wan_switch_dpid"
-    __SW_PORT_PARAM = "wan_switch_port"
+    __WAN_SERVICE_ENDPOINT_PARAM = "service_endpoint_id"
+    __WAN_MAPPING_INFO_PARAM = "service_mapping_info"
+    __SW_ID_PARAM = "switch_dpid"
+    __SW_PORT_PARAM = "switch_port"
     __VLAN_PARAM = "vlan"
 
     # Public functions exposed to the Resource Orchestrator
-    def __init__(self, wim, wim_account, config):
-        self.logger = logging.getLogger(self.__WIM_LOGGER)
+    def __init__(self, wim, wim_account, config=None, logger=None):
+        self.logger = logger or logging.getLogger(self.__WIM_LOGGER)
+        super().__init__(wim, wim_account, config, self.logger)
         self.__wim = wim
         self.__wim_account = wim_account
         self.__config = config
         self.__wim_url = self.__wim.get("wim_url")
         self.__user = wim_account.get("user")
-        self.__passwd = wim_account.get("passwd")
+        self.__passwd = wim_account.get("password")
         self.logger.info("Initialized.")
 
-    def create_connectivity_service(self,
-                                    service_type,
-                                    connection_points,
-                                    **kwargs):
+    def create_connectivity_service(self, service_type, connection_points, **kwargs):
         self.__check_service(service_type, connection_points, kwargs)
 
         body = self.__get_body(service_type, connection_points, kwargs)
@@ -110,7 +108,7 @@
     def edit_connectivity_service(self, service_uuid,
                                   conn_info, connection_points,
                                   **kwargs):
-        self.__exception(WimError.UNSUPPORTED_FEATURE, http_code=501)
+        self.__exception(SdnError.UNSUPPORTED_FEATURE, http_code=501)
 
     def get_connectivity_service_status(self, service_uuid):
         endpoint = "{}/service/status/{}".format(self.__wim_url, service_uuid)
@@ -120,7 +118,7 @@
             self.__exception(e.message, http_code=503)
 
         if response.status_code != 200:
-            self.__exception(WimError.STATUS, http_code=response.status_code)
+            self.__exception(SdnError.STATUS, http_code=response.status_code)
         self.logger.info("Status for service with uuid {}: {}"
                          .format(service_uuid, response.content))
         return response.content
@@ -132,7 +130,7 @@
         except requests.exceptions.RequestException as e:
             self.__exception(e.message, http_code=503)
         if response.status_code != 200:
-            self.__exception(WimError.DELETE, http_code=response.status_code)
+            self.__exception(SdnError.DELETE, http_code=response.status_code)
 
         self.logger.info("Service with uuid: {} deleted".format(service_uuid))
 
@@ -144,7 +142,7 @@
         except requests.exceptions.RequestException as e:
             self.__exception(e.message, http_code=503)
         if http_code != 200:
-            self.__exception(WimError.CLEAR_ALL, http_code=http_code)
+            self.__exception(SdnError.CLEAR_ALL, http_code=http_code)
 
         self.logger.info("{} services deleted".format(response.content))
         return "{} services deleted".format(response.content)
@@ -159,7 +157,7 @@
             self.__exception(e.message, http_code=503)
 
         if http_code != 200:
-            self.__exception(WimError.UNREACHABLE, http_code=http_code)
+            self.__exception(SdnError.UNREACHABLE, http_code=http_code)
         self.logger.info("Connectivity checked")
 
     def check_credentials(self):
@@ -173,7 +171,7 @@
             self.__exception(e.message, http_code=503)
 
         if http_code != 200:
-            self.__exception(WimError.UNAUTHORIZED, http_code=http_code)
+            self.__exception(SdnError.UNAUTHORIZED, http_code=http_code)
         self.logger.info("Credentials checked")
 
     # Private functions
@@ -184,29 +182,29 @@
         else:
             error = x
         self.logger.error(error)
-        raise WimConnectorError(error, http_code=http_code)
+        raise SdnConnectorError(error, http_code=http_code)
 
     def __check_service(self, service_type, connection_points, kwargs):
         if service_type not in self.__supported_service_types:
-            self.__exception(WimError.SERVICE_TYPE_ERROR, http_code=400)
+            self.__exception(SdnError.SERVICE_TYPE_ERROR, http_code=400)
 
         if len(connection_points) != 2:
-            self.__exception(WimError.CONNECTION_POINTS_SIZE, http_code=400)
+            self.__exception(SdnError.CONNECTION_POINTS_SIZE, http_code=400)
 
         for connection_point in connection_points:
             enc_type = connection_point.get(self.__ENCAPSULATION_TYPE_PARAM)
             if enc_type not in self.__supported_encapsulation_types:
-                self.__exception(WimError.ENCAPSULATION_TYPE, http_code=400)
+                self.__exception(SdnError.ENCAPSULATION_TYPE, http_code=400)
 
         # Commented out for as long as parameter isn't implemented
         # bandwidth = kwargs.get(self.__BANDWIDTH_PARAM)
         # if not isinstance(bandwidth, int):
-            # self.__exception(WimError.BANDWIDTH, http_code=400)
+            # self.__exception(SdnError.BANDWIDTH, http_code=400)
 
         # Commented out for as long as parameter isn't implemented
         # backup = kwargs.get(self.__BACKUP_PARAM)
         # if not isinstance(backup, bool):
-            # self.__exception(WimError.BACKUP, http_code=400)
+            # self.__exception(SdnError.BACKUP, http_code=400)
 
     def __get_body(self, service_type, connection_points, kwargs):
         port_mapping = self.__config.get("service_endpoint_mapping")
diff --git a/RO-SDN-dynpac/requirements.txt b/RO-SDN-dynpac/requirements.txt
new file mode 100644
index 0000000..44c797f
--- /dev/null
+++ b/RO-SDN-dynpac/requirements.txt
@@ -0,0 +1,18 @@
+##
+# 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.
+##
+
+requests
+git+https://osm.etsi.org/gerrit/osm/RO.git#egg=osm-ro
+
diff --git a/RO-SDN-dynpac/setup.py b/RO-SDN-dynpac/setup.py
new file mode 100644
index 0000000..46d25e1
--- /dev/null
+++ b/RO-SDN-dynpac/setup.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+##
+# 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.
+##
+
+from setuptools import setup
+
+_name = "osm_rosdn_dynpac"
+
+README = """
+===========
+osm-rosdn_dynpac
+===========
+
+osm-ro pluging for dynpac SDN
+"""
+
+setup(
+    name=_name,
+    description='OSM ro sdn plugin for dynpac',
+    long_description=README,
+    version_command=('git describe --match v* --tags --long --dirty', 'pep440-git-full'),
+    # version=VERSION,
+    # python_requires='>3.5.0',
+    author='ETSI OSM',
+    # TODO py3 author_email='',
+    maintainer='OSM_TECH@LIST.ETSI.ORG',  # TODO py3
+    # TODO py3 maintainer_email='',
+    url='https://osm.etsi.org/gitweb/?p=osm/RO.git;a=summary',
+    license='Apache 2.0',
+
+    packages=[_name],
+    include_package_data=True,
+    dependency_links=["git+https://osm.etsi.org/gerrit/osm/RO.git#egg=osm-ro"],
+    install_requires=["requests", "osm-ro"],
+    setup_requires=['setuptools-version-command'],
+    entry_points={
+        'osm_rosdn.plugins': ['rosdn_dynpac = osm_rosdn_dynpac.wimconn_dynpac'],
+    },
+)
diff --git a/RO-SDN-dynpac/stdeb.cfg b/RO-SDN-dynpac/stdeb.cfg
new file mode 100644
index 0000000..0c718e4
--- /dev/null
+++ b/RO-SDN-dynpac/stdeb.cfg
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
+[DEFAULT]
+X-Python3-Version : >= 3.5
+Depends3: python3-requests, python3-osm-ro
+
diff --git a/RO-SDN-dynpac/tox.ini b/RO-SDN-dynpac/tox.ini
new file mode 100644
index 0000000..a1e866a
--- /dev/null
+++ b/RO-SDN-dynpac/tox.ini
@@ -0,0 +1,41 @@
+##
+# 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.
+##
+
+[tox]
+envlist = py3
+toxworkdir={homedir}/.tox
+
+[testenv]
+basepython = python3
+install_command = python3 -m pip install -r requirements.txt -U {opts} {packages}
+# deps = -r{toxinidir}/test-requirements.txt
+commands=python3 -m unittest discover -v
+
+[testenv:flake8]
+basepython = python3
+deps = flake8
+commands = flake8 osm_rosdn_dynpac --max-line-length 120 \
+    --exclude .svn,CVS,.gz,.git,__pycache__,.tox,local,temp --ignore W291,W293,E226,W504
+
+[testenv:unittest]
+basepython = python3
+commands = python3 -m unittest osm_rosdn_dynpac.tests
+
+[testenv:build]
+basepython = python3
+deps = stdeb
+       setuptools-version-command
+commands = python3 setup.py --command-packages=stdeb.command bdist_deb
+
diff --git a/RO-SDN-onos_openflow/Makefile b/RO-SDN-onos_openflow/Makefile
new file mode 100644
index 0000000..5e96ce0
--- /dev/null
+++ b/RO-SDN-onos_openflow/Makefile
@@ -0,0 +1,24 @@
+##
+# 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.
+##
+
+all: clean package
+
+clean:
+	rm -rf dist deb_dist osm_rosdn_onosof-*.tar.gz osm_rosdn_onosof.egg-info .eggs
+
+package:
+	python3 setup.py --command-packages=stdeb.command sdist_dsc
+	cd deb_dist/osm-rosdn-onosof*/ && dpkg-buildpackage -rfakeroot -uc -us
+
diff --git a/RO-SDN-onos_openflow/osm_rosdn_onosof/onos_of.py b/RO-SDN-onos_openflow/osm_rosdn_onosof/onos_of.py
new file mode 100644
index 0000000..060d1d3
--- /dev/null
+++ b/RO-SDN-onos_openflow/osm_rosdn_onosof/onos_of.py
@@ -0,0 +1,469 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+##
+# Copyright 2016, I2T Research Group (UPV/EHU)
+# This file is part of openvim
+# All Rights Reserved.
+#
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: alaitz.mendiola@ehu.eus or alaitz.mendiola@gmail.com
+##
+
+'''
+ImplementS the pluging for the Open Network Operating System (ONOS) openflow
+controller. It creates the class OF_conn to create dataplane connections
+with static rules based on packet destination MAC address
+'''
+
+__author__="Alaitz Mendiola"
+__date__ ="$22-nov-2016$"
+
+
+import json
+import requests
+import base64
+import logging
+from osm_ro.wim.openflow_conn import OpenflowConn, OpenflowConnException, OpenflowConnConnectionException, \
+    OpenflowConnUnexpectedResponse, OpenflowConnAuthException, OpenflowConnNotFoundException, \
+    OpenflowConnConflictException, OpenflowConnNotSupportedException, OpenflowConnNotImplemented
+
+
+class OfConnOnos(OpenflowConn):
+    """
+    ONOS connector. No MAC learning is used
+    """
+    def __init__(self, params):
+        """ Constructor.
+            Params: dictionary with the following keys:
+                of_dpid:     DPID to use for this controller ?? Does a controller have a dpid?
+                url:         must be [http://HOST:PORT/
+                of_user:     user credentials, can be missing or None
+                of_password: password credentials
+                of_debug:    debug level for logging. Default to ERROR
+                other keys are ignored
+            Raise an exception if same parameter is missing or wrong
+        """
+
+        OpenflowConn.__init__(self, params)
+
+        # check params
+        url = params.get("of_url")
+        if not url:
+            raise ValueError("'url' must be provided")
+        if not url.startswith("http"):
+            url = "http://" + url
+        if not url.endswith("/"):
+            url = url + "/"
+        self.url = url + "onos/v1/"
+
+        #internal variables
+        self.name = "onosof"
+        self.headers = {'content-type':'application/json','accept':'application/json',}
+
+        self.auth="None"
+        self.pp2ofi={}  # From Physical Port to OpenFlow Index
+        self.ofi2pp={}  # From OpenFlow Index to Physical Port
+
+        self.dpid = str(params["of_dpid"])
+        self.id = 'of:'+str(self.dpid.replace(':', ''))
+
+        # TODO This may not be straightforward
+        if params.get("of_user"):
+            of_password=params.get("of_password", "")
+            self.auth = base64.b64encode(bytes(params["of_user"] + ":" + of_password, "utf-8"))
+            self.auth = self.auth.decode()
+            self.headers['authorization'] = 'Basic ' + self.auth
+
+        self.logger = logging.getLogger('vim.OF.onos')
+        self.logger.setLevel( getattr(logging, params.get("of_debug", "ERROR")) )
+        self.ip_address = None
+
+    def get_of_switches(self):
+        """
+        Obtain a a list of switches or DPID detected by this controller
+        :return: list where each element a tuple pair (DPID, IP address)
+                 Raise a openflowconnUnexpectedResponse expection in case of failure
+        """
+        try:
+            self.headers['content-type'] = 'text/plain'
+            of_response = requests.get(self.url + "devices", headers=self.headers)
+            error_text = "Openflow response %d: %s" % (of_response.status_code, of_response.text)
+            if of_response.status_code != 200:
+                self.logger.warning("get_of_switches " + error_text)
+                raise OpenflowConnUnexpectedResponse(error_text)
+
+            self.logger.debug("get_of_switches " + error_text)
+            info = of_response.json()
+
+            if type(info) != dict:
+                self.logger.error("get_of_switches. Unexpected response, not a dict: %s", str(info))
+                raise OpenflowConnUnexpectedResponse("Unexpected response, not a dict. Wrong version?")
+
+            node_list = info.get('devices')
+
+            if type(node_list) is not list:
+                self.logger.error(
+                    "get_of_switches. Unexpected response, at 'devices', not found or not a list: %s",
+                    str(type(node_list)))
+                raise OpenflowConnUnexpectedResponse("Unexpected response, at 'devices', not found "
+                                                                   "or not a list. Wrong version?")
+
+            switch_list = []
+            for node in node_list:
+                node_id = node.get('id')
+                if node_id is None:
+                    self.logger.error("get_of_switches. Unexpected response at 'device':'id', not found: %s",
+                                      str(node))
+                    raise OpenflowConnUnexpectedResponse("Unexpected response at 'device':'id', "
+                                                                       "not found . Wrong version?")
+
+                node_ip_address = node.get('annotations').get('managementAddress')
+                if node_ip_address is None:
+                    self.logger.error(
+                        "get_of_switches. Unexpected response at 'device':'managementAddress', not found: %s",
+                        str(node))
+                    raise OpenflowConnUnexpectedResponse(
+                        "Unexpected response at 'device':'managementAddress', not found. Wrong version?")
+
+                node_id_hex = hex(int(node_id.split(':')[1])).split('x')[1].zfill(16)
+
+                switch_list.append(
+                    (':'.join(a + b for a, b in zip(node_id_hex[::2], node_id_hex[1::2])), node_ip_address))
+            return switch_list
+
+        except requests.exceptions.RequestException as e:
+            error_text = type(e).__name__ + ": " + str(e)
+            self.logger.error("get_of_switches " + error_text)
+            raise OpenflowConnConnectionException(error_text)
+        except ValueError as e:
+            # ValueError in the case that JSON can not be decoded
+            error_text = type(e).__name__ + ": " + str(e)
+            self.logger.error("get_of_switches " + error_text)
+            raise OpenflowConnUnexpectedResponse(error_text)
+
+    def obtain_port_correspondence(self):
+        """
+        Obtain the correspondence between physical and openflow port names
+        :return: dictionary with physical name as key, openflow name as value
+                 Raise a openflowconnUnexpectedResponse expection in case of failure
+        """
+        try:
+            self.headers['content-type'] = 'text/plain'
+            of_response = requests.get(self.url + "devices/" + self.id + "/ports", headers=self.headers)
+            error_text = "Openflow response %d: %s" % (of_response.status_code, of_response.text)
+            if of_response.status_code != 200:
+                self.logger.warning("obtain_port_correspondence " + error_text)
+                raise OpenflowConnUnexpectedResponse(error_text)
+
+            self.logger.debug("obtain_port_correspondence " + error_text)
+            info = of_response.json()
+
+            node_connector_list = info.get('ports')
+            if type(node_connector_list) is not list:
+                self.logger.error(
+                    "obtain_port_correspondence. Unexpected response at 'ports', not found or not a list: %s",
+                    str(node_connector_list))
+                raise OpenflowConnUnexpectedResponse("Unexpected response at 'ports', not found  or not "
+                                                                   "a list. Wrong version?")
+
+            for node_connector in node_connector_list:
+                if node_connector['port'] != "local":
+                    self.pp2ofi[str(node_connector['annotations']['portName'])] = str(node_connector['port'])
+                    self.ofi2pp[str(node_connector['port'])] = str(node_connector['annotations']['portName'])
+
+            node_ip_address = info['annotations']['managementAddress']
+            if node_ip_address is None:
+                self.logger.error(
+                    "obtain_port_correspondence. Unexpected response at 'managementAddress', not found: %s",
+                    str(self.id))
+                raise OpenflowConnUnexpectedResponse("Unexpected response at 'managementAddress', "
+                                                                   "not found. Wrong version?")
+            self.ip_address = node_ip_address
+
+            # print self.name, ": obtain_port_correspondence ports:", self.pp2ofi
+            return self.pp2ofi
+        except requests.exceptions.RequestException as e:
+            error_text = type(e).__name__ + ": " + str(e)
+            self.logger.error("obtain_port_correspondence " + error_text)
+            raise OpenflowConnConnectionException(error_text)
+        except ValueError as e:
+            # ValueError in the case that JSON can not be decoded
+            error_text = type(e).__name__ + ": " + str(e)
+            self.logger.error("obtain_port_correspondence " + error_text)
+            raise OpenflowConnUnexpectedResponse(error_text)
+
+    def get_of_rules(self, translate_of_ports=True):
+        """
+        Obtain the rules inserted at openflow controller
+        :param translate_of_ports: if True it translates ports from openflow index to physical switch name
+        :return: list where each item is a  dictionary with the following content:
+                    priority: rule priority
+                    name:         rule name (present also as the master dict key)
+                    ingress_port: match input port of the rule
+                    dst_mac:      match destination mac address of the rule, can be missing or None if not apply
+                    vlan_id:      match vlan tag of the rule, can be missing or None if not apply
+                    actions:      list of actions, composed by a pair tuples:
+                        (vlan, None/int): for stripping/setting a vlan tag
+                        (out, port):      send to this port
+                    switch:       DPID, all
+                 Raise a openflowconnUnexpectedResponse expection in case of failure
+        """
+
+        try:
+
+            if len(self.ofi2pp) == 0:
+                self.obtain_port_correspondence()
+
+            # get rules
+            self.headers['content-type'] = 'text/plain'
+            of_response = requests.get(self.url + "flows/" + self.id, headers=self.headers)
+            error_text = "Openflow response %d: %s" % (of_response.status_code, of_response.text)
+
+            # The configured page does not exist if there are no rules installed. In that case we return an empty dict
+            if of_response.status_code == 404:
+                return {}
+
+            elif of_response.status_code != 200:
+                self.logger.warning("get_of_rules " + error_text)
+                raise OpenflowConnUnexpectedResponse(error_text)
+            self.logger.debug("get_of_rules " + error_text)
+
+            info = of_response.json()
+
+            if type(info) != dict:
+                self.logger.error("get_of_rules. Unexpected response, not a dict: %s", str(info))
+                raise OpenflowConnUnexpectedResponse("Unexpected openflow response, not a dict. "
+                                                                   "Wrong version?")
+
+            flow_list = info.get('flows')
+
+            if flow_list is None:
+                return {}
+
+            if type(flow_list) is not list:
+                self.logger.error(
+                    "get_of_rules. Unexpected response at 'flows', not a list: %s",
+                    str(type(flow_list)))
+                raise OpenflowConnUnexpectedResponse("Unexpected response at 'flows', not a list. "
+                                                                   "Wrong version?")
+
+            rules = [] # Response list
+            for flow in flow_list:
+                if not ('id' in flow and 'selector' in flow and 'treatment' in flow and \
+                                    'instructions' in flow['treatment'] and 'criteria' in \
+                                    flow['selector']):
+                    raise OpenflowConnUnexpectedResponse("unexpected openflow response, one or more "
+                                                                       "elements are missing. Wrong version?")
+
+                rule = dict()
+                rule['switch'] = self.dpid
+                rule['priority'] = flow.get('priority')
+                rule['name'] = flow['id']
+
+                for criteria in flow['selector']['criteria']:
+                    if criteria['type'] == 'IN_PORT':
+                        in_port = str(criteria['port'])
+                        if in_port != "CONTROLLER":
+                            if not in_port in self.ofi2pp:
+                                raise OpenflowConnUnexpectedResponse("Error: Ingress port {} is not "
+                                                                                   "in switch port list".format(in_port))
+                            if translate_of_ports:
+                                in_port = self.ofi2pp[in_port]
+                        rule['ingress_port'] = in_port
+
+                    elif criteria['type'] == 'VLAN_VID':
+                        rule['vlan_id'] = criteria['vlanId']
+
+                    elif criteria['type'] == 'ETH_DST':
+                        rule['dst_mac'] = str(criteria['mac']).lower()
+
+                actions = []
+                for instruction in flow['treatment']['instructions']:
+                    if instruction['type'] == "OUTPUT":
+                        out_port = str(instruction['port'])
+                        if out_port != "CONTROLLER":
+                            if not out_port in self.ofi2pp:
+                                raise OpenflowConnUnexpectedResponse("Error: Output port {} is not in "
+                                                                                   "switch port list".format(out_port))
+
+                            if translate_of_ports:
+                                out_port = self.ofi2pp[out_port]
+
+                        actions.append( ('out', out_port) )
+
+                    if instruction['type'] == "L2MODIFICATION" and instruction['subtype'] == "VLAN_POP":
+                        actions.append( ('vlan', 'None') )
+                    if instruction['type'] == "L2MODIFICATION" and instruction['subtype'] == "VLAN_ID":
+                        actions.append( ('vlan', instruction['vlanId']) )
+
+                rule['actions'] = actions
+                rules.append(rule)
+            return rules
+
+        except requests.exceptions.RequestException as e:
+            # ValueError in the case that JSON can not be decoded
+            error_text = type(e).__name__ + ": " + str(e)
+            self.logger.error("get_of_rules " + error_text)
+            raise OpenflowConnConnectionException(error_text)
+        except ValueError as e:
+            # ValueError in the case that JSON can not be decoded
+            error_text = type(e).__name__ + ": " + str(e)
+            self.logger.error("get_of_rules " + error_text)
+            raise OpenflowConnUnexpectedResponse(error_text)
+
+    def del_flow(self, flow_name):
+        """
+        Delete an existing rule
+        :param flow_name:
+        :return: Raise a openflowconnUnexpectedResponse expection in case of failure
+        """
+
+        try:
+            self.headers['content-type'] = None
+            of_response = requests.delete(self.url + "flows/" + self.id + "/" + flow_name, headers=self.headers)
+            error_text = "Openflow response %d: %s" % (of_response.status_code, of_response.text)
+
+            if of_response.status_code != 204:
+                self.logger.warning("del_flow " + error_text)
+                raise OpenflowConnUnexpectedResponse(error_text)
+
+            self.logger.debug("del_flow OK " + error_text)
+            return None
+
+        except requests.exceptions.RequestException as e:
+            error_text = type(e).__name__ + ": " + str(e)
+            self.logger.error("del_flow " + error_text)
+            raise OpenflowConnConnectionException(error_text)
+
+    def new_flow(self, data):
+        """
+        Insert a new static rule
+        :param data: dictionary with the following content:
+                priority:     rule priority
+                name:         rule name
+                ingress_port: match input port of the rule
+                dst_mac:      match destination mac address of the rule, missing or None if not apply
+                vlan_id:      match vlan tag of the rule, missing or None if not apply
+                actions:      list of actions, composed by a pair tuples with these posibilities:
+                    ('vlan', None/int): for stripping/setting a vlan tag
+                    ('out', port):      send to this port
+        :return: Raise a openflowconnUnexpectedResponse expection in case of failure
+        """
+        try:
+
+            if len(self.pp2ofi) == 0:
+                self.obtain_port_correspondence()
+
+            # Build the dictionary with the flow rule information for ONOS
+            flow = dict()
+            #flow['id'] = data['name']
+            flow['tableId'] = 0
+            flow['priority'] = data.get('priority')
+            flow['timeout'] = 0
+            flow['isPermanent'] = "true"
+            flow['appId'] = 10 # FIXME We should create an appId for OSM
+            flow['selector'] = dict()
+            flow['selector']['criteria'] = list()
+
+            # Flow rule matching criteria
+            if not data['ingress_port'] in self.pp2ofi:
+                error_text = 'Error. Port ' + data['ingress_port'] + ' is not present in the switch'
+                self.logger.warning("new_flow " + error_text)
+                raise OpenflowConnUnexpectedResponse(error_text)
+
+            ingress_port_criteria = dict()
+            ingress_port_criteria['type'] = "IN_PORT"
+            ingress_port_criteria['port'] = self.pp2ofi[data['ingress_port']]
+            flow['selector']['criteria'].append(ingress_port_criteria)
+
+            if 'dst_mac' in data:
+                dst_mac_criteria = dict()
+                dst_mac_criteria["type"] = "ETH_DST"
+                dst_mac_criteria["mac"] = data['dst_mac']
+                flow['selector']['criteria'].append(dst_mac_criteria)
+
+            if data.get('vlan_id'):
+                vlan_criteria = dict()
+                vlan_criteria["type"] = "VLAN_VID"
+                vlan_criteria["vlanId"] = int(data['vlan_id'])
+                flow['selector']['criteria'].append(vlan_criteria)
+
+            # Flow rule treatment
+            flow['treatment'] = dict()
+            flow['treatment']['instructions'] = list()
+            flow['treatment']['deferred'] = list()
+
+            for action in data['actions']:
+                new_action = dict()
+                if  action[0] == "vlan":
+                    new_action['type'] = "L2MODIFICATION"
+                    if action[1] == None:
+                        new_action['subtype'] = "VLAN_POP"
+                    else:
+                        new_action['subtype'] = "VLAN_ID"
+                        new_action['vlanId'] = int(action[1])
+                elif action[0] == 'out':
+                    new_action['type'] = "OUTPUT"
+                    if not action[1] in self.pp2ofi:
+                        error_msj = 'Port '+ action[1] + ' is not present in the switch'
+                        raise OpenflowConnUnexpectedResponse(error_msj)
+                    new_action['port'] = self.pp2ofi[action[1]]
+                else:
+                    error_msj = "Unknown item '%s' in action list" % action[0]
+                    self.logger.error("new_flow " + error_msj)
+                    raise OpenflowConnUnexpectedResponse(error_msj)
+
+                flow['treatment']['instructions'].append(new_action)
+
+            self.headers['content-type'] = 'application/json'
+            path = self.url + "flows/" + self.id
+            of_response = requests.post(path, headers=self.headers, data=json.dumps(flow) )
+
+            error_text = "Openflow response %d: %s" % (of_response.status_code, of_response.text)
+            if of_response.status_code != 201:
+                self.logger.warning("new_flow " + error_text)
+                raise OpenflowConnUnexpectedResponse(error_text)
+
+            flowId = of_response.headers['location'][path.__len__() + 1:]
+
+            data['name'] = flowId
+
+            self.logger.debug("new_flow OK " + error_text)
+            return None
+
+        except requests.exceptions.RequestException as e:
+            error_text = type(e).__name__ + ": " + str(e)
+            self.logger.error("new_flow " + error_text)
+            raise OpenflowConnConnectionException(error_text)
+
+    def clear_all_flows(self):
+        """
+        Delete all existing rules
+        :return: Raise a openflowconnUnexpectedResponse expection in case of failure
+        """
+        try:
+            rules = self.get_of_rules(True)
+
+            for rule in rules:
+                self.del_flow(rule)
+
+            self.logger.debug("clear_all_flows OK ")
+            return None
+
+        except requests.exceptions.RequestException as e:
+            error_text = type(e).__name__ + ": " + str(e)
+            self.logger.error("clear_all_flows " + error_text)
+            raise OpenflowConnConnectionException(error_text)
diff --git a/RO-SDN-onos_openflow/osm_rosdn_onosof/sdnconn_onosof.py b/RO-SDN-onos_openflow/osm_rosdn_onosof/sdnconn_onosof.py
new file mode 100644
index 0000000..79c1441
--- /dev/null
+++ b/RO-SDN-onos_openflow/osm_rosdn_onosof/sdnconn_onosof.py
@@ -0,0 +1,41 @@
+##
+# Copyright 2019 Telefonica Investigacion y Desarrollo, S.A.U.
+# All Rights Reserved.
+#
+# 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.
+#
+##
+"""The SdnConnectorOnosOf connector is responsible for creating services using pro active operflow rules.
+"""
+
+import logging
+from osm_ro.wim.openflow_conn import SdnConnectorOpenFlow
+from .onos_of import OfConnOnos
+
+
+class SdnConnectorOnosOf(SdnConnectorOpenFlow):
+
+    def __init__(self, wim, wim_account, config=None, logger=None):
+        """Creates a connectivity based on pro-active openflow rules
+        """
+        self.logger = logging.getLogger('openmano.sdnconn.onosof')
+        super().__init__(wim, wim_account, config, logger)
+        of_params = {
+            "of_url": wim["wim_url"],
+            "of_dpid": config.get("dpid"),
+            "of_user": wim_account["user"],
+            "of_password": wim_account["password"],
+        }
+        self.openflow_conn = OfConnOnos(of_params)
+        super().__init__(wim, wim_account, config, logger, self.openflow_conn)
diff --git a/RO-SDN-onos_openflow/requirements.txt b/RO-SDN-onos_openflow/requirements.txt
new file mode 100644
index 0000000..44c797f
--- /dev/null
+++ b/RO-SDN-onos_openflow/requirements.txt
@@ -0,0 +1,18 @@
+##
+# 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.
+##
+
+requests
+git+https://osm.etsi.org/gerrit/osm/RO.git#egg=osm-ro
+
diff --git a/RO-SDN-onos_openflow/setup.py b/RO-SDN-onos_openflow/setup.py
new file mode 100644
index 0000000..380adc7
--- /dev/null
+++ b/RO-SDN-onos_openflow/setup.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+##
+# 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.
+##
+
+from setuptools import setup
+
+_name = "osm_rosdn_onosof"
+
+README = """
+===========
+osm-rosdn_onosof
+===========
+
+osm-ro pluging for onosof (ietfl2vpn) SDN
+"""
+
+setup(
+    name=_name,
+    description='OSM ro sdn plugin for onosof (ietfl2vpn)',
+    long_description=README,
+    version_command=('git describe --match v* --tags --long --dirty', 'pep440-git-full'),
+    # version=VERSION,
+    # python_requires='>3.5.0',
+    author='ETSI OSM',
+    author_email='alfonso.tiernosepulveda@telefonica.com',
+    maintainer='Alfonso Tierno',
+    maintainer_email='alfonso.tiernosepulveda@telefonica.com',
+    url='https://osm.etsi.org/gitweb/?p=osm/RO.git;a=summary',
+    license='Apache 2.0',
+
+    packages=[_name],
+    include_package_data=True,
+    dependency_links=["git+https://osm.etsi.org/gerrit/osm/RO.git#egg=osm-ro"],
+    install_requires=["requests", "osm-ro"],
+    setup_requires=['setuptools-version-command'],
+    entry_points={
+        'osm_rosdn.plugins': ['rosdn_onosof = osm_rosdn_onosof.sdnconn_onosof:SdnConnectorOnosOf'],
+    },
+)
diff --git a/RO-SDN-onos_openflow/stdeb.cfg b/RO-SDN-onos_openflow/stdeb.cfg
new file mode 100644
index 0000000..0c718e4
--- /dev/null
+++ b/RO-SDN-onos_openflow/stdeb.cfg
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
+[DEFAULT]
+X-Python3-Version : >= 3.5
+Depends3: python3-requests, python3-osm-ro
+
diff --git a/RO-SDN-onos_openflow/tox.ini b/RO-SDN-onos_openflow/tox.ini
new file mode 100644
index 0000000..00b4585
--- /dev/null
+++ b/RO-SDN-onos_openflow/tox.ini
@@ -0,0 +1,41 @@
+##
+# 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.
+##
+
+[tox]
+envlist = py3
+toxworkdir={homedir}/.tox
+
+[testenv]
+basepython = python3
+install_command = python3 -m pip install -r requirements.txt -U {opts} {packages}
+# deps = -r{toxinidir}/test-requirements.txt
+commands=python3 -m unittest discover -v
+
+[testenv:flake8]
+basepython = python3
+deps = flake8
+commands = flake8 osm_rosdn_onosof --max-line-length 120 \
+    --exclude .svn,CVS,.gz,.git,__pycache__,.tox,local,temp --ignore W291,W293,E226,W504
+
+[testenv:unittest]
+basepython = python3
+commands = python3 -m unittest osm_rosdn_onosof.tests
+
+[testenv:build]
+basepython = python3
+deps = stdeb
+       setuptools-version-command
+commands = python3 setup.py --command-packages=stdeb.command bdist_deb
+
diff --git a/RO-SDN-tapi/Makefile b/RO-SDN-tapi/Makefile
new file mode 100644
index 0000000..2e05280
--- /dev/null
+++ b/RO-SDN-tapi/Makefile
@@ -0,0 +1,24 @@
+##
+# 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.
+##
+
+all: clean package
+
+clean:
+	rm -rf dist deb_dist osm_rosdn_tapi-*.tar.gz osm_rosdn_tapi.egg-info .eggs
+
+package:
+	python3 setup.py --command-packages=stdeb.command sdist_dsc
+	cd deb_dist/osm-rosdn-tapi*/ && dpkg-buildpackage -rfakeroot -uc -us
+
diff --git a/osm_ro/wim/wimconn_ietfl2vpn.py b/RO-SDN-tapi/osm_rosdn_tapi/wimconn_ietfl2vpn.py
similarity index 85%
rename from osm_ro/wim/wimconn_ietfl2vpn.py
rename to RO-SDN-tapi/osm_rosdn_tapi/wimconn_ietfl2vpn.py
index dc7cc97..26680b5 100644
--- a/osm_ro/wim/wimconn_ietfl2vpn.py
+++ b/RO-SDN-tapi/osm_rosdn_tapi/wimconn_ietfl2vpn.py
@@ -21,10 +21,10 @@
 # funded by the European Commission under Grant number 761727 through the
 # Horizon 2020 program.
 ##
-"""The WIM connector is responsible for establishing wide area network
+"""The SDN/WIM connector is responsible for establishing wide area network
 connectivity.
 
-This WIM connector implements the standard IETF RFC 8466 "A YANG Data
+This SDN/WIM connector implements the standard IETF RFC 8466 "A YANG Data
  Model for Layer 2 Virtual Private Network (L2VPN) Service Delivery"
 
 It receives the endpoints and the necessary details to request
@@ -33,11 +33,11 @@
 import requests
 import uuid
 import logging
-from .wimconn import WimConnector, WimConnectorError
+from osm_ro.wim.sdnconn import SdnConnectorBase, SdnConnectorError
 """CHeck layer where we move it"""
 
 
-class WimconnectorIETFL2VPN(WimConnector):
+class WimconnectorIETFL2VPN(SdnConnectorBase):
 
     def __init__(self, wim, wim_account, config=None, logger=None):
         """IETF L2VPM WIM connector
@@ -46,13 +46,13 @@
             wim (dict): WIM record, as stored in the database
             wim_account (dict): WIM account record, as stored in the database
         """
-        self.logger = logging.getLogger('openmano.wimconn.ietfl2vpn')
-        super(WimconnectorIETFL2VPN, self).__init__(wim, wim_account, config, logger)
+        self.logger = logging.getLogger('openmano.sdnconn.ietfl2vpn')
+        super().__init__(wim, wim_account, config, logger)
         self.headers = {'Content-Type': 'application/json'}
-        self.mappings = {m['wan_service_endpoint_id']: m
+        self.mappings = {m['service_endpoint_id']: m
                          for m in self.service_endpoint_mapping}
         self.user = wim_account.get("user")
-        self.passwd = wim_account.get("passwd")
+        self.passwd = wim_account.get("passwordd")
         if self.user and self.passwd is not None:
             self.auth = (self.user, self.passwd)
         else:
@@ -65,10 +65,10 @@
             response = requests.get(endpoint, auth=self.auth)    
             http_code = response.status_code
         except requests.exceptions.RequestException as e:
-            raise WimConnectorError(e.message, http_code=503)
+            raise SdnConnectorError(e.message, http_code=503)
 
         if http_code != 200:
-            raise WimConnectorError("Failed while authenticating", http_code=http_code)
+            raise SdnConnectorError("Failed while authenticating", http_code=http_code)
         self.logger.info("Credentials checked")
 
     def get_connectivity_service_status(self, service_uuid, conn_info=None):
@@ -79,10 +79,10 @@
 
         Returns:
             Examples::
-                {'wim_status': 'ACTIVE'}
-                {'wim_status': 'INACTIVE'}
-                {'wim_status': 'DOWN'}
-                {'wim_status': 'ERROR'}
+                {'sdn_status': 'ACTIVE'}
+                {'sdn_status': 'INACTIVE'}
+                {'sdn_status': 'DOWN'}
+                {'sdn_status': 'ERROR'}
         """
         try:
             self.logger.info("Sending get connectivity service stuatus")
@@ -90,16 +90,16 @@
                 self.wim["wim_url"], service_uuid)
             response = requests.get(servicepoint, auth=self.auth)
             if response.status_code != requests.codes.ok:
-                raise WimConnectorError("Unable to obtain connectivity servcice status", http_code=response.status_code)
-            service_status = {'wim_status': 'ACTIVE'}
+                raise SdnConnectorError("Unable to obtain connectivity servcice status", http_code=response.status_code)
+            service_status = {'sdn_status': 'ACTIVE'}
             return service_status
         except requests.exceptions.ConnectionError:
-            raise WimConnectorError("Request Timeout", http_code=408)
+            raise SdnConnectorError("Request Timeout", http_code=408)
                
     def search_mapp(self, connection_point):
         id = connection_point['service_endpoint_id']
         if id not in self.mappings:         
-            raise WimConnectorError("Endpoint {} not located".format(str(id)))
+            raise SdnConnectorError("Endpoint {} not located".format(str(id)))
         else:
             return self.mappings[id]
 
@@ -147,13 +147,13 @@
                  **MUST** be JSON/YAML-serializable (plain data structures).
 
         Raises:
-            WimConnectorException: In case of error.
+            SdnConnectorException: In case of error.
         """
         if service_type == "ELINE":
             if len(connection_points) > 2:
-                raise WimConnectorError('Connections between more than 2 endpoints are not supported')
+                raise SdnConnectorError('Connections between more than 2 endpoints are not supported')
             if len(connection_points) < 2:
-                raise WimConnectorError('Connections must be of at least 2 endpoints')
+                raise SdnConnectorError('Connections must be of at least 2 endpoints')
             """ First step, create the vpn service """    
             uuid_l2vpn = str(uuid.uuid4())
             vpn_service = {}
@@ -173,11 +173,11 @@
                 response_service_creation = requests.post(endpoint_service_creation, headers=self.headers,
                                                           json=vpn_service_l, auth=self.auth)
             except requests.exceptions.ConnectionError:
-                raise WimConnectorError("Request to create service Timeout", http_code=408)
+                raise SdnConnectorError("Request to create service Timeout", http_code=408)
             if response_service_creation.status_code == 409:
-                raise WimConnectorError("Service already exists", http_code=response_service_creation.status_code)
+                raise SdnConnectorError("Service already exists", http_code=response_service_creation.status_code)
             elif response_service_creation.status_code != requests.codes.created:
-                raise WimConnectorError("Request to create service not accepted",
+                raise SdnConnectorError("Request to create service not accepted",
                                         http_code=response_service_creation.status_code)
             """ Second step, create the connections and vpn attachments """   
             for connection_point in connection_points:
@@ -192,7 +192,7 @@
                         tagged_interf = {}
                         service_endpoint_encapsulation_info = connection_point["service_endpoint_encapsulation_info"]
                         if service_endpoint_encapsulation_info["vlan"] is None:
-                            raise WimConnectorError("VLAN must be provided")
+                            raise SdnConnectorError("VLAN must be provided")
                         tagged_interf["cvlan-id"] = service_endpoint_encapsulation_info["vlan"]
                         tagged["dot1q-vlan-tagged"] = tagged_interf
                         connection["tagged-interface"] = tagged
@@ -207,20 +207,20 @@
                 self.logger.info("Sending vpn-attachement :{}".format(vpn_attach))
                 uuid_sna = str(uuid.uuid4())
                 site_network_access["network-access-id"] = uuid_sna
-                site_network_access["bearer"] = connection_point_wan_info["wan_service_mapping_info"]["bearer"]
+                site_network_access["bearer"] = connection_point_wan_info["service_mapping_info"]["bearer"]
                 site_network_accesses = {}
                 site_network_access_list = []
                 site_network_access_list.append(site_network_access)
                 site_network_accesses["ietf-l2vpn-svc:site-network-access"] = site_network_access_list
                 conn_info_d = {}
-                conn_info_d["site"] = connection_point_wan_info["wan_service_mapping_info"]["site-id"]
+                conn_info_d["site"] = connection_point_wan_info["service_mapping_info"]["site-id"]
                 conn_info_d["site-network-access-id"] = site_network_access["network-access-id"]
                 conn_info_d["mapping"] = None
                 conn_info.append(conn_info_d)
                 try:
                     endpoint_site_network_access_creation = \
                         "{}/restconf/data/ietf-l2vpn-svc:l2vpn-svc/sites/site={}/site-network-accesses/".format(
-                            self.wim["wim_url"], connection_point_wan_info["wan_service_mapping_info"]["site-id"])
+                            self.wim["wim_url"], connection_point_wan_info["service_mapping_info"]["site-id"])
                     response_endpoint_site_network_access_creation = requests.post(
                         endpoint_site_network_access_creation,
                         headers=self.headers,
@@ -229,25 +229,25 @@
                     
                     if response_endpoint_site_network_access_creation.status_code == 409:
                         self.delete_connectivity_service(vpn_service["vpn-id"])
-                        raise WimConnectorError("Site_Network_Access with ID '{}' already exists".format(
+                        raise SdnConnectorError("Site_Network_Access with ID '{}' already exists".format(
                             site_network_access["network-access-id"]),
                             http_code=response_endpoint_site_network_access_creation.status_code)
                     
                     elif response_endpoint_site_network_access_creation.status_code == 400:
                         self.delete_connectivity_service(vpn_service["vpn-id"])
-                        raise WimConnectorError("Site {} does not exist".format(
-                            connection_point_wan_info["wan_service_mapping_info"]["site-id"]),
+                        raise SdnConnectorError("Site {} does not exist".format(
+                            connection_point_wan_info["service_mapping_info"]["site-id"]),
                             http_code=response_endpoint_site_network_access_creation.status_code)
                     
                     elif response_endpoint_site_network_access_creation.status_code != requests.codes.created and \
                             response_endpoint_site_network_access_creation.status_code != requests.codes.no_content:
                         self.delete_connectivity_service(vpn_service["vpn-id"])
-                        raise WimConnectorError("Request no accepted",
+                        raise SdnConnectorError("Request no accepted",
                                                 http_code=response_endpoint_site_network_access_creation.status_code)
                 
                 except requests.exceptions.ConnectionError:
                     self.delete_connectivity_service(vpn_service["vpn-id"])
-                    raise WimConnectorError("Request Timeout", http_code=408)
+                    raise SdnConnectorError("Request Timeout", http_code=408)
             return uuid_l2vpn, conn_info
         
         else:
@@ -265,9 +265,9 @@
                 self.wim["wim_url"], service_uuid)
             response = requests.delete(servicepoint, auth=self.auth)
             if response.status_code != requests.codes.no_content:
-                raise WimConnectorError("Error in the request", http_code=response.status_code)
+                raise SdnConnectorError("Error in the request", http_code=response.status_code)
         except requests.exceptions.ConnectionError:
-            raise WimConnectorError("Request Timeout", http_code=408)
+            raise SdnConnectorError("Request Timeout", http_code=408)
 
     def edit_connectivity_service(self, service_uuid, conn_info=None,
                                   connection_points=None, **kwargs):
@@ -283,7 +283,7 @@
             site_network_access = {}
             connection_point_wan_info = self.search_mapp(connection_point)
             params_site = {}
-            params_site["site-id"] = connection_point_wan_info["wan_service_mapping_info"]["site-id"]
+            params_site["site-id"] = connection_point_wan_info["service_mapping_info"]["site-id"]
             params_site["site-vpn-flavor"] = "site-vpn-flavor-single"
             device_site = {}
             device_site["device-id"] = connection_point_wan_info["device-id"]
@@ -298,7 +298,7 @@
                     tagged_interf = {}
                     service_endpoint_encapsulation_info = connection_point["service_endpoint_encapsulation_info"]
                     if service_endpoint_encapsulation_info["vlan"] is None:
-                        raise WimConnectorError("VLAN must be provided")
+                        raise SdnConnectorError("VLAN must be provided")
                     tagged_interf["cvlan-id"] = service_endpoint_encapsulation_info["vlan"]
                     tagged["dot1q-vlan-tagged"] = tagged_interf
                     connection["tagged-interface"] = tagged
@@ -311,7 +311,7 @@
             site_network_access["vpn-attachment"] = vpn_attach
             uuid_sna = conn_info[counter]["site-network-access-id"]
             site_network_access["network-access-id"] = uuid_sna
-            site_network_access["bearer"] = connection_point_wan_info["wan_service_mapping_info"]["bearer"]
+            site_network_access["bearer"] = connection_point_wan_info["service_mapping_info"]["bearer"]
             site_network_accesses = {}
             site_network_access_list = []
             site_network_access_list.append(site_network_access)
@@ -319,20 +319,20 @@
             try:
                 endpoint_site_network_access_edit = \
                     "{}/restconf/data/ietf-l2vpn-svc:l2vpn-svc/sites/site={}/site-network-accesses/".format(
-                        self.wim["wim_url"], connection_point_wan_info["wan_service_mapping_info"]["site-id"])
+                        self.wim["wim_url"], connection_point_wan_info["service_mapping_info"]["site-id"])
                 response_endpoint_site_network_access_creation = requests.put(endpoint_site_network_access_edit,
                                                                               headers=self.headers,
                                                                               json=site_network_accesses,
                                                                               auth=self.auth)
                 if response_endpoint_site_network_access_creation.status_code == 400:
-                    raise WimConnectorError("Service does not exist",
+                    raise SdnConnectorError("Service does not exist",
                                             http_code=response_endpoint_site_network_access_creation.status_code)
                 elif response_endpoint_site_network_access_creation.status_code != 201 and \
                         response_endpoint_site_network_access_creation.status_code != 204:
-                    raise WimConnectorError("Request no accepted",
+                    raise SdnConnectorError("Request no accepted",
                                             http_code=response_endpoint_site_network_access_creation.status_code)
             except requests.exceptions.ConnectionError:
-                raise WimConnectorError("Request Timeout", http_code=408)
+                raise SdnConnectorError("Request Timeout", http_code=408)
             counter += 1
         return None
 
@@ -343,9 +343,9 @@
             servicepoint = "{}/restconf/data/ietf-l2vpn-svc:l2vpn-svc/vpn-services".format(self.wim["wim_url"])
             response = requests.delete(servicepoint, auth=self.auth)
             if response.status_code != requests.codes.no_content:
-                raise WimConnectorError("Unable to clear all connectivity services", http_code=response.status_code)
+                raise SdnConnectorError("Unable to clear all connectivity services", http_code=response.status_code)
         except requests.exceptions.ConnectionError:
-            raise WimConnectorError("Request Timeout", http_code=408)
+            raise SdnConnectorError("Request Timeout", http_code=408)
 
     def get_all_active_connectivity_services(self):
         """Provide information about all active connections provisioned by a
@@ -356,7 +356,7 @@
             servicepoint = "{}/restconf/data/ietf-l2vpn-svc:l2vpn-svc/vpn-services".format(self.wim["wim_url"])
             response = requests.get(servicepoint, auth=self.auth)
             if response.status_code != requests.codes.ok:
-                raise WimConnectorError("Unable to get all connectivity services", http_code=response.status_code)
+                raise SdnConnectorError("Unable to get all connectivity services", http_code=response.status_code)
             return response
         except requests.exceptions.ConnectionError:
-            raise WimConnectorError("Request Timeout", http_code=408)
+            raise SdnConnectorError("Request Timeout", http_code=408)
diff --git a/RO-SDN-tapi/requirements.txt b/RO-SDN-tapi/requirements.txt
new file mode 100644
index 0000000..44c797f
--- /dev/null
+++ b/RO-SDN-tapi/requirements.txt
@@ -0,0 +1,18 @@
+##
+# 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.
+##
+
+requests
+git+https://osm.etsi.org/gerrit/osm/RO.git#egg=osm-ro
+
diff --git a/RO-SDN-tapi/setup.py b/RO-SDN-tapi/setup.py
new file mode 100644
index 0000000..931dd66
--- /dev/null
+++ b/RO-SDN-tapi/setup.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+##
+# 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.
+##
+
+from setuptools import setup
+
+_name = "osm_rosdn_tapi"
+
+README = """
+===========
+osm-rosdn_tapi
+===========
+
+osm-ro pluging for tapi (ietfl2vpn) SDN
+"""
+
+setup(
+    name=_name,
+    description='OSM ro sdn plugin for tapi (ietfl2vpn)',
+    long_description=README,
+    version_command=('git describe --match v* --tags --long --dirty', 'pep440-git-full'),
+    # version=VERSION,
+    # python_requires='>3.5.0',
+    author='ETSI OSM',
+    # TODO py3 author_email='',
+    maintainer='OSM_TECH@LIST.ETSI.ORG',  # TODO py3
+    # TODO py3 maintainer_email='',
+    url='https://osm.etsi.org/gitweb/?p=osm/RO.git;a=summary',
+    license='Apache 2.0',
+
+    packages=[_name],
+    include_package_data=True,
+    dependency_links=["git+https://osm.etsi.org/gerrit/osm/RO.git#egg=osm-ro"],
+    install_requires=["requests", "osm-ro"],
+    setup_requires=['setuptools-version-command'],
+    entry_points={
+        'osm_rosdn.plugins': ['rosdn_tapi = osm_rosdn_tapi.wimconn_ietfl2vpn:WimconnectorIETFL2VPN'],
+    },
+)
diff --git a/RO-SDN-tapi/stdeb.cfg b/RO-SDN-tapi/stdeb.cfg
new file mode 100644
index 0000000..0c718e4
--- /dev/null
+++ b/RO-SDN-tapi/stdeb.cfg
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
+[DEFAULT]
+X-Python3-Version : >= 3.5
+Depends3: python3-requests, python3-osm-ro
+
diff --git a/RO-SDN-tapi/tox.ini b/RO-SDN-tapi/tox.ini
new file mode 100644
index 0000000..7d643cd
--- /dev/null
+++ b/RO-SDN-tapi/tox.ini
@@ -0,0 +1,41 @@
+##
+# 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.
+##
+
+[tox]
+envlist = py3
+toxworkdir={homedir}/.tox
+
+[testenv]
+basepython = python3
+install_command = python3 -m pip install -r requirements.txt -U {opts} {packages}
+# deps = -r{toxinidir}/test-requirements.txt
+commands=python3 -m unittest discover -v
+
+[testenv:flake8]
+basepython = python3
+deps = flake8
+commands = flake8 osm_rosdn_tapi --max-line-length 120 \
+    --exclude .svn,CVS,.gz,.git,__pycache__,.tox,local,temp --ignore W291,W293,E226,W504
+
+[testenv:unittest]
+basepython = python3
+commands = python3 -m unittest osm_rosdn_tapi.tests
+
+[testenv:build]
+basepython = python3
+deps = stdeb
+       setuptools-version-command
+commands = python3 setup.py --command-packages=stdeb.command bdist_deb
+
diff --git a/RO-VIM-aws/Makefile b/RO-VIM-aws/Makefile
new file mode 100644
index 0000000..edf3eb7
--- /dev/null
+++ b/RO-VIM-aws/Makefile
@@ -0,0 +1,23 @@
+##
+# 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.
+##
+
+all: clean package
+
+clean:
+	rm -rf dist deb_dist osm_rovim_aws-*.tar.gz osm_rovim_aws.egg-info .eggs
+
+package:
+	python3 setup.py --command-packages=stdeb.command sdist_dsc
+	cd deb_dist/osm-rovim-aws*/ && dpkg-buildpackage -rfakeroot -uc -us
diff --git a/osm_ro/vimconn_aws.py b/RO-VIM-aws/osm_rovim_aws/vimconn_aws.py
similarity index 98%
rename from osm_ro/vimconn_aws.py
rename to RO-VIM-aws/osm_rovim_aws/vimconn_aws.py
index 40530f6..28dc4e9 100644
--- a/osm_ro/vimconn_aws.py
+++ b/RO-VIM-aws/osm_rovim_aws/vimconn_aws.py
@@ -28,18 +28,15 @@
 __author__ = "Saboor Ahmad"
 __date__ = "10-Apr-2017"
 
-import vimconn
+from osm_ro import vimconn
 import yaml
 import logging
 import netaddr
 import time
 
-try:
-    import boto
-    import boto.ec2
-    import boto.vpc
-except:
-    exit("Boto not avialable. Try activating your virtualenv OR `pip install boto`")
+import boto
+import boto.ec2
+import boto.vpc
 
 
 class vimconnector(vimconn.vimconnector):
@@ -111,9 +108,9 @@
                 try:
                     if flavor_data[0] == "@":  # read from a file
                         with open(flavor_data[1:], 'r') as stream:
-                            self.flavor_info = yaml.load(stream)
+                            self.flavor_info = yaml.load(stream, Loader=yaml.Loader)
                     else:
-                        self.flavor_info = yaml.load(flavor_data)
+                        self.flavor_info = yaml.load(flavor_data, Loader=yaml.Loader)
                 except yaml.YAMLError as e:
                     self.flavor_info = None
                     raise vimconn.vimconnException("Bad format at file '{}': {}".format(flavor_data[1:], e))
@@ -480,7 +477,7 @@
         self.logger.debug("Getting flavor id from data")
         try:
             flavor = None
-            for key, values in self.flavor_info.iteritems():
+            for key, values in self.flavor_info.items():
                 if (values["ram"], values["cpus"], values["disk"]) == (
                 flavor_dict["ram"], flavor_dict["vcpus"], flavor_dict["disk"]):
                     flavor = (key, values)
diff --git a/RO-VIM-aws/requirements.txt b/RO-VIM-aws/requirements.txt
new file mode 100644
index 0000000..3cbc851
--- /dev/null
+++ b/RO-VIM-aws/requirements.txt
@@ -0,0 +1,20 @@
+##
+# 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.
+##
+
+PyYAML
+requests
+netaddr
+boto
+git+https://osm.etsi.org/gerrit/osm/RO.git#egg=osm-ro&subdirectory=RO
diff --git a/RO-VIM-aws/setup.py b/RO-VIM-aws/setup.py
new file mode 100644
index 0000000..30b90bd
--- /dev/null
+++ b/RO-VIM-aws/setup.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+##
+# 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.
+##
+
+from setuptools import setup
+
+_name = "osm_rovim_aws"
+
+README = """
+===========
+osm-rovim_aws
+===========
+
+osm-ro pluging for aws VIM
+"""
+
+setup(
+    name=_name,
+    description='OSM ro vim plugin for aws',
+    long_description=README,
+    version_command=('git describe --match v* --tags --long --dirty', 'pep440-git-full'),
+    # version=VERSION,
+    # python_requires='>3.5.0',
+    author='ETSI OSM',
+    # TODO py3 author_email='',
+    maintainer='OSM_TECH@LIST.ETSI.ORG',  # TODO py3
+    # TODO py3 maintainer_email='',
+    url='https://osm.etsi.org/gitweb/?p=osm/RO.git;a=summary',
+    license='Apache 2.0',
+
+    packages=[_name],
+    include_package_data=True,
+    dependency_links=["git+https://osm.etsi.org/gerrit/osm/RO.git#egg=osm-ro"],
+    install_requires=[
+        "requests", "netaddr", "PyYAML", "osm-ro", "boto"
+    ],
+    setup_requires=['setuptools-version-command'],
+    entry_points={
+        'osm_rovim.plugins': ['rovim_aws = osm_rovim_aws.vimconn_aws'],
+    },
+)
diff --git a/RO-VIM-aws/stdeb.cfg b/RO-VIM-aws/stdeb.cfg
new file mode 100644
index 0000000..2193709
--- /dev/null
+++ b/RO-VIM-aws/stdeb.cfg
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+[DEFAULT]
+X-Python3-Version : >= 3.5
+Depends3: python3-boto, python3-requests, python3-netaddr, python3-yaml, python3-osm-ro
diff --git a/RO-VIM-aws/tox.ini b/RO-VIM-aws/tox.ini
new file mode 100644
index 0000000..067b0d4
--- /dev/null
+++ b/RO-VIM-aws/tox.ini
@@ -0,0 +1,41 @@
+##
+# 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.
+##
+
+[tox]
+envlist = py3
+toxworkdir={homedir}/.tox
+
+[testenv]
+basepython = python3
+install_command = python3 -m pip install -r requirements.txt -U {opts} {packages}
+# deps = -r{toxinidir}/test-requirements.txt
+commands=python3 -m unittest discover -v
+
+[testenv:flake8]
+basepython = python3
+deps = flake8
+commands = flake8 osm_rovim_aws --max-line-length 120 \
+    --exclude .svn,CVS,.gz,.git,__pycache__,.tox,local,temp --ignore W291,W293,E226,W504
+
+[testenv:unittest]
+basepython = python3
+commands = python3 -m unittest osm_rovim_aws.tests
+
+[testenv:build]
+basepython = python3
+deps = stdeb
+       setuptools-version-command
+commands = python3 setup.py --command-packages=stdeb.command bdist_deb
+
diff --git a/RO-VIM-azure/Makefile b/RO-VIM-azure/Makefile
new file mode 100644
index 0000000..d5b779a
--- /dev/null
+++ b/RO-VIM-azure/Makefile
@@ -0,0 +1,25 @@
+##
+# 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.
+##
+
+all: clean package
+
+clean:
+	rm -rf dist deb_dist osm_rovim_azure-*.tar.gz osm_rovim_azure.egg-info .eggs
+
+package:
+	python3 setup.py --command-packages=stdeb.command sdist_dsc
+	cp debian/python3-osm-rovim-azure.postinst deb_dist/osm-rovim-azure*/debian/
+	cd deb_dist/osm-rovim-azure*/ && dpkg-buildpackage -rfakeroot -uc -us
+
diff --git a/RO-VIM-azure/debian/python3-osm-rovim-azure.postinst b/RO-VIM-azure/debian/python3-osm-rovim-azure.postinst
new file mode 100755
index 0000000..ebb69b1
--- /dev/null
+++ b/RO-VIM-azure/debian/python3-osm-rovim-azure.postinst
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+##
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: OSM_TECH@list.etsi.org
+##
+
+echo "POST INSTALL OSM-ROVIM-AZURE"
+
+#Pip packages required for azure connector
+python3 -m pip install azure
+
diff --git a/osm_ro/vimconn_azure.py b/RO-VIM-azure/osm_rovim_azure/vimconn_azure.py
similarity index 100%
rename from osm_ro/vimconn_azure.py
rename to RO-VIM-azure/osm_rovim_azure/vimconn_azure.py
diff --git a/RO-VIM-azure/requirements.txt b/RO-VIM-azure/requirements.txt
new file mode 100644
index 0000000..6cfff52
--- /dev/null
+++ b/RO-VIM-azure/requirements.txt
@@ -0,0 +1,20 @@
+##
+# 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.
+##
+
+PyYAML
+requests
+netaddr
+azure
+git+https://osm.etsi.org/gerrit/osm/RO.git#egg=osm-ro&subdirectory=RO
diff --git a/RO-VIM-azure/setup.py b/RO-VIM-azure/setup.py
new file mode 100644
index 0000000..557feda
--- /dev/null
+++ b/RO-VIM-azure/setup.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+##
+# 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.
+##
+
+from setuptools import setup
+
+_name = "osm_rovim_azure"
+
+README = """
+===========
+osm-rovim_azure
+===========
+
+osm-ro pluging for azure VIM
+"""
+
+setup(
+    name=_name,
+    description='OSM ro vim plugin for azure',
+    long_description=README,
+    version_command=('git describe --match v* --tags --long --dirty', 'pep440-git-full'),
+    # version=VERSION,
+    # python_requires='>3.5.0',
+    author='ETSI OSM',
+    author_email='alfonso.tiernosepulveda@telefonica.com',
+    maintainer='Alfonso Tierno',
+    maintainer_email='alfonso.tiernosepulveda@telefonica.com',
+    url='https://osm.etsi.org/gitweb/?p=osm/RO.git;a=summary',
+    license='Apache 2.0',
+
+    packages=[_name],
+    include_package_data=True,
+    dependency_links=["git+https://osm.etsi.org/gerrit/osm/RO.git#egg=osm-ro"],
+    install_requires=["requests", "netaddr", "PyYAML", "azure", "osm-ro"],
+    setup_requires=['setuptools-version-command'],
+    entry_points={
+        'osm_rovim.plugins': ['rovim_azure = osm_rovim_azure.vimconn_azure'],
+    },
+)
diff --git a/RO-VIM-azure/stdeb.cfg b/RO-VIM-azure/stdeb.cfg
new file mode 100644
index 0000000..968c55e
--- /dev/null
+++ b/RO-VIM-azure/stdeb.cfg
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
+[DEFAULT]
+X-Python3-Version : >= 3.5
+Depends3: python3-requests, python3-netaddr, python3-yaml, python3-osm-ro, python3-pip
+
diff --git a/RO-VIM-azure/tox.ini b/RO-VIM-azure/tox.ini
new file mode 100644
index 0000000..9bc1472
--- /dev/null
+++ b/RO-VIM-azure/tox.ini
@@ -0,0 +1,41 @@
+##
+# 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.
+##
+
+[tox]
+envlist = py3
+toxworkdir={homedir}/.tox
+
+[testenv]
+basepython = python3
+install_command = python3 -m pip install -r requirements.txt -U {opts} {packages}
+# deps = -r{toxinidir}/test-requirements.txt
+commands=python3 -m unittest discover -v
+
+[testenv:flake8]
+basepython = python3
+deps = flake8
+commands = flake8 osm_rovim_azure --max-line-length 120 \
+    --exclude .svn,CVS,.gz,.git,__pycache__,.tox,local,temp --ignore W291,W293,E226,W504
+
+[testenv:unittest]
+basepython = python3
+commands = python3 -m unittest osm_rovim_azure.tests
+
+[testenv:build]
+basepython = python3
+deps = stdeb
+       setuptools-version-command
+commands = python3 setup.py --command-packages=stdeb.command bdist_deb
+
diff --git a/RO-VIM-fos/Makefile b/RO-VIM-fos/Makefile
new file mode 100644
index 0000000..2693453
--- /dev/null
+++ b/RO-VIM-fos/Makefile
@@ -0,0 +1,24 @@
+##
+# 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.
+##
+
+all: clean package
+
+clean:
+	rm -rf dist deb_dist osm_rovim_fos-*.tar.gz osm_rovim_fos.egg-info .eggs
+
+package:
+	python3 setup.py --command-packages=stdeb.command sdist_dsc
+	cp debian/python3-osm-rovim-fos.postinst deb_dist/osm-rovim-fos*/debian/
+	cd deb_dist/osm-rovim-fos*/ && dpkg-buildpackage -rfakeroot -uc -us
diff --git a/RO-VIM-fos/debian/python3-osm-rovim-fos.postinst b/RO-VIM-fos/debian/python3-osm-rovim-fos.postinst
new file mode 100755
index 0000000..744b26f
--- /dev/null
+++ b/RO-VIM-fos/debian/python3-osm-rovim-fos.postinst
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+##
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: OSM_TECH@list.etsi.org
+##
+
+echo "POST INSTALL OSM-ROVIM-FOS"
+
+#Pip packages required for vmware connector
+python3 -m pip install fog05rest>=0.0.4
+
diff --git a/osm_ro/vimconn_fos.py b/RO-VIM-fos/osm_rovim_fos/vimconn_fos.py
similarity index 99%
rename from osm_ro/vimconn_fos.py
rename to RO-VIM-fos/osm_rovim_fos/vimconn_fos.py
index d101d46..c30c1f1 100644
--- a/osm_ro/vimconn_fos.py
+++ b/RO-VIM-fos/osm_rovim_fos/vimconn_fos.py
@@ -37,7 +37,7 @@
 import uuid
 import socket
 import struct
-import vimconn
+from . import vimconn
 import random
 import yaml
 from functools import partial
diff --git a/RO-VIM-fos/requirements.txt b/RO-VIM-fos/requirements.txt
new file mode 100644
index 0000000..0164a30
--- /dev/null
+++ b/RO-VIM-fos/requirements.txt
@@ -0,0 +1,20 @@
+##
+# 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.
+##
+
+PyYAML
+requests
+netaddr
+fog05rest>=0.0.4
+git+https://osm.etsi.org/gerrit/osm/RO.git#egg=osm-ro&subdirectory=RO
diff --git a/RO-VIM-fos/setup.py b/RO-VIM-fos/setup.py
new file mode 100644
index 0000000..95d97ca
--- /dev/null
+++ b/RO-VIM-fos/setup.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+##
+# 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.
+##
+
+from setuptools import setup
+
+_name = "osm_rovim_fos"
+
+README = """
+===========
+osm-rovim_fos
+===========
+
+osm-ro pluging for fos VIM
+"""
+
+setup(
+    name=_name,
+    description='OSM ro vim plugin for fos',
+    long_description=README,
+    version_command=('git describe --match v* --tags --long --dirty', 'pep440-git-full'),
+    # version=VERSION,
+    # python_requires='>3.5.0',
+    author='ETSI OSM',
+    # TODO py3 author_email='',
+    maintainer='OSM_TECH@LIST.ETSI.ORG',  # TODO py3
+    # TODO py3 maintainer_email='',
+    url='https://osm.etsi.org/gitweb/?p=osm/RO.git;a=summary',
+    license='Apache 2.0',
+
+    packages=[_name],
+    include_package_data=True,
+    dependency_links=["git+https://osm.etsi.org/gerrit/osm/RO.git#egg=osm-ro"],
+    install_requires=[
+        "requests", "netaddr", "PyYAML", "osm-ro", "fog05rest>=0.0.4"
+    ],
+    setup_requires=['setuptools-version-command'],
+    entry_points={
+        'osm_rovim.plugins': ['rovim_fos = osm_rovim_fos.vimconn_fos'],
+    },
+)
diff --git a/RO-VIM-fos/stdeb.cfg b/RO-VIM-fos/stdeb.cfg
new file mode 100644
index 0000000..cf4b353
--- /dev/null
+++ b/RO-VIM-fos/stdeb.cfg
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+[DEFAULT]
+X-Python3-Version : >= 3.5
+Depends3: python3-pip, python3-requests, python3-netaddr, python3-yaml, python3-osm-ro
diff --git a/RO-VIM-fos/tox.ini b/RO-VIM-fos/tox.ini
new file mode 100644
index 0000000..297800b
--- /dev/null
+++ b/RO-VIM-fos/tox.ini
@@ -0,0 +1,41 @@
+##
+# 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.
+##
+
+[tox]
+envlist = py3
+toxworkdir={homedir}/.tox
+
+[testenv]
+basepython = python3
+install_command = python3 -m pip install -r requirements.txt -U {opts} {packages}
+# deps = -r{toxinidir}/test-requirements.txt
+commands=python3 -m unittest discover -v
+
+[testenv:flake8]
+basepython = python3
+deps = flake8
+commands = flake8 osm_rovim_fos --max-line-length 120 \
+    --exclude .svn,CVS,.gz,.git,__pycache__,.tox,local,temp --ignore W291,W293,E226,W504
+
+[testenv:unittest]
+basepython = python3
+commands = python3 -m unittest osm_rovim_fos.tests
+
+[testenv:build]
+basepython = python3
+deps = stdeb
+       setuptools-version-command
+commands = python3 setup.py --command-packages=stdeb.command bdist_deb
+
diff --git a/RO-VIM-opennebula/Makefile b/RO-VIM-opennebula/Makefile
new file mode 100644
index 0000000..2ec6a44
--- /dev/null
+++ b/RO-VIM-opennebula/Makefile
@@ -0,0 +1,26 @@
+##
+# Copyright 2017  Telefonica Digital Spain S.L.U.
+# 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.
+##
+
+all: clean package
+
+clean:
+	rm -rf dist deb_dist osm_rovim_opennebula-*.tar.gz osm_rovim_opennebula.egg-info .eggs
+
+package:
+	python3 setup.py --command-packages=stdeb.command sdist_dsc
+	cp debian/python3-osm-rovim-opennebula.postinst deb_dist/osm-rovim-opennebula*/debian/
+	cd deb_dist/osm-rovim-opennebula*/ && dpkg-buildpackage -rfakeroot -uc -us
+
diff --git a/RO-VIM-opennebula/debian/python3-osm-rovim-opennebula.postinst b/RO-VIM-opennebula/debian/python3-osm-rovim-opennebula.postinst
new file mode 100755
index 0000000..27aacc7
--- /dev/null
+++ b/RO-VIM-opennebula/debian/python3-osm-rovim-opennebula.postinst
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+##
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: OSM_TECH@list.etsi.org
+##
+
+echo "POST INSTALL OSM-ROVIM-OPENNEBULA"
+
+#Pip packages required for opennebula connector
+python3 -m pip install -e git+https://github.com/python-oca/python-oca#egg=oca
+python3 -m pip install untangle
+python3 -m pip install pyone
+
diff --git a/osm_ro/vimconn_opennebula.py b/RO-VIM-opennebula/osm_rovim_opennebula/vimconn_opennebula.py
similarity index 98%
rename from osm_ro/vimconn_opennebula.py
rename to RO-VIM-opennebula/osm_rovim_opennebula/vimconn_opennebula.py
index 56aabe7..d788dcb 100644
--- a/osm_ro/vimconn_opennebula.py
+++ b/RO-VIM-opennebula/osm_rovim_opennebula/vimconn_opennebula.py
@@ -28,7 +28,7 @@
 __author__ = "Jose Maria Carmona Perez,Juan Antonio Hernando Labajo, Emilio Abraham Garrido Garcia,Alberto Florez " \
              "Pages, Andres Pozo Munoz, Santiago Perez Marin, Onlife Networks Telefonica I+D Product Innovation "
 __date__ = "$13-dec-2017 11:09:29$"
-import vimconn
+from osm_ro import vimconn
 import requests
 import logging
 import oca
@@ -193,12 +193,12 @@
             else:
                 index = ip_profile["subnet_address"].find("/")
                 ip_start = ip_profile["subnet_address"][:index]
-                if "dhcp_count" in ip_profile.keys() and ip_profile["dhcp_count"] is not None:
+                if "dhcp_count" in ip_profile and ip_profile["dhcp_count"] is not None:
                     size = str(ip_profile["dhcp_count"])
-                elif not ("dhcp_count" in ip_profile.keys()) and ip_profile["ip_version"] == "IPv4":
+                elif "dhcp_count" not in ip_profile and ip_profile["ip_version"] == "IPv4":
                     prefix = ip_profile["subnet_address"][index + 1:]
                     size = int(math.pow(2, 32 - prefix))
-                if "dhcp_start_address" in ip_profile.keys() and ip_profile["dhcp_start_address"] is not None:
+                if "dhcp_start_address" in ip_profile and ip_profile["dhcp_start_address"] is not None:
                     ip_start = str(ip_profile["dhcp_start_address"])
                 if ip_profile["ip_version"] == "IPv6":
                     ip_prefix_type = "GLOBAL_PREFIX"
@@ -257,11 +257,11 @@
             one = self._new_one_connection()
             net_pool = one.vnpool.info(-2, -1, -1).VNET
             response = []
-            if "name" in filter_dict.keys():
+            if "name" in filter_dict:
                 network_name_filter = filter_dict["name"]
             else:
                 network_name_filter = None
-            if "id" in filter_dict.keys():
+            if "id" in filter_dict:
                 network_id_filter = filter_dict["id"]
             else:
                 network_id_filter = None
@@ -453,11 +453,11 @@
             one = self._new_one_connection()
             image_pool = one.imagepool.info(-2, -1, -1).IMAGE
             images = []
-            if "name" in filter_dict.keys():
+            if "name" in filter_dict:
                 image_name_filter = filter_dict["name"]
             else:
                 image_name_filter = None
-            if "id" in filter_dict.keys():
+            if "id" in filter_dict:
                 image_id_filter = filter_dict["id"]
             else:
                 image_id_filter = None
diff --git a/RO-VIM-opennebula/requirements.txt b/RO-VIM-opennebula/requirements.txt
new file mode 100644
index 0000000..71b09d8
--- /dev/null
+++ b/RO-VIM-opennebula/requirements.txt
@@ -0,0 +1,23 @@
+##
+# Copyright 2017  Telefonica Digital Spain S.L.U.
+# 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.
+##
+
+PyYAML
+requests
+netaddr
+untangle
+pyone
+git+https://github.com/python-oca/python-oca#egg=oca
+git+https://osm.etsi.org/gerrit/osm/RO.git#egg=osm-ro&subdirectory=RO
diff --git a/RO-VIM-opennebula/setup.py b/RO-VIM-opennebula/setup.py
new file mode 100644
index 0000000..c27bca3
--- /dev/null
+++ b/RO-VIM-opennebula/setup.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+##
+# Copyright 2017  Telefonica Digital Spain S.L.U.
+# 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.
+##
+
+from setuptools import setup
+
+_name = "osm_rovim_opennebula"
+
+README = """
+===========
+osm-rovim_opennebula
+===========
+
+osm-ro pluging for opennebula VIM
+"""
+
+setup(
+    name=_name,
+    description='OSM ro vim plugin for opennebula',
+    long_description=README,
+    version_command=('git describe --match v* --tags --long --dirty', 'pep440-git-full'),
+    # version=VERSION,
+    # python_requires='>3.5.0',
+    author='ETSI OSM',
+    # TODO py3 author_email='',
+    maintainer='OSM_TECH@LIST.ETSI.ORG',  # TODO py3
+    # TODO py3 maintainer_email='',
+    url='https://osm.etsi.org/gitweb/?p=osm/RO.git;a=summary',
+    license='Apache 2.0',
+
+    packages=[_name],
+    include_package_data=True,
+    dependency_links=["git+https://osm.etsi.org/gerrit/osm/RO.git#egg=osm-ro"],
+    install_requires=["requests", "netaddr", "PyYAML", "osm-ro",],
+    setup_requires=['setuptools-version-command'],
+    entry_points={
+        'osm_rovim.plugins': ['rovim_opennebula = osm_rovim_opennebula.vimconn_opennebula'],
+    },
+)
diff --git a/RO-VIM-opennebula/stdeb.cfg b/RO-VIM-opennebula/stdeb.cfg
new file mode 100644
index 0000000..00071bd
--- /dev/null
+++ b/RO-VIM-opennebula/stdeb.cfg
@@ -0,0 +1,20 @@
+#
+# Copyright 2017  Telefonica Digital Spain S.L.U.
+# 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.
+#
+
+[DEFAULT]
+X-Python3-Version : >= 3.5
+Depends3: python3-requests, python3-netaddr, python3-yaml, python3-osm-ro, python3-pip
+
diff --git a/RO-VIM-opennebula/tox.ini b/RO-VIM-opennebula/tox.ini
new file mode 100644
index 0000000..6fb9d37
--- /dev/null
+++ b/RO-VIM-opennebula/tox.ini
@@ -0,0 +1,42 @@
+##
+# Copyright 2017  Telefonica Digital Spain S.L.U.
+# 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.
+##
+
+[tox]
+envlist = py3
+toxworkdir={homedir}/.tox
+
+[testenv]
+basepython = python3
+install_command = python3 -m pip install -r requirements.txt -U {opts} {packages}
+# deps = -r{toxinidir}/test-requirements.txt
+commands=python3 -m unittest discover -v
+
+[testenv:flake8]
+basepython = python3
+deps = flake8
+commands = flake8 osm_rovim_opennebula --max-line-length 120 \
+    --exclude .svn,CVS,.gz,.git,__pycache__,.tox,local,temp --ignore W291,W293,E226,W504
+
+[testenv:unittest]
+basepython = python3
+commands = python3 -m unittest osm_rovim_opennebula.tests
+
+[testenv:build]
+basepython = python3
+deps = stdeb
+       setuptools-version-command
+commands = python3 setup.py --command-packages=stdeb.command bdist_deb
+
diff --git a/RO-VIM-openstack/Makefile b/RO-VIM-openstack/Makefile
new file mode 100644
index 0000000..dfafea3
--- /dev/null
+++ b/RO-VIM-openstack/Makefile
@@ -0,0 +1,25 @@
+##
+# 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.
+##
+
+all: clean package
+
+clean:
+	rm -rf dist deb_dist osm_rovim_openstack-*.tar.gz osm_rovim_openstack.egg-info .eggs
+
+package:
+	python3 setup.py --command-packages=stdeb.command sdist_dsc
+	cp debian/python3-osm-rovim-openstack.postinst deb_dist/osm-rovim-openstack*/debian/
+	cd deb_dist/osm-rovim-openstack*/ && dpkg-buildpackage -rfakeroot -uc -us
+
diff --git a/RO-VIM-openstack/debian/python3-osm-rovim-openstack.postinst b/RO-VIM-openstack/debian/python3-osm-rovim-openstack.postinst
new file mode 100755
index 0000000..055d4a5
--- /dev/null
+++ b/RO-VIM-openstack/debian/python3-osm-rovim-openstack.postinst
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+##
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: OSM_TECH@list.etsi.org
+##
+
+echo "POST INSTALL OSM-ROVIM-OPENSTACK"
+
+#Pip packages required for openstack connector
+python3 -m pip install networking-l2gw
diff --git a/osm_ro/tests/test_vimconn_openstack.py b/RO-VIM-openstack/osm_rovim_openstack/tests/test_vimconn_openstack.py
similarity index 100%
rename from osm_ro/tests/test_vimconn_openstack.py
rename to RO-VIM-openstack/osm_rovim_openstack/tests/test_vimconn_openstack.py
diff --git a/osm_ro/vimconn_openstack.py b/RO-VIM-openstack/osm_rovim_openstack/vimconn_openstack.py
similarity index 97%
rename from osm_ro/vimconn_openstack.py
rename to RO-VIM-openstack/osm_rovim_openstack/vimconn_openstack.py
index 8d87b7f..15ef713 100644
--- a/osm_ro/vimconn_openstack.py
+++ b/RO-VIM-openstack/osm_rovim_openstack/vimconn_openstack.py
@@ -16,9 +16,6 @@
 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 # License for the specific language governing permissions and limitations
 # under the License.
-#
-# For those usages not covered by the Apache License, Version 2.0 please
-# contact with: nfvlabs@tid.es
 ##
 
 '''
@@ -35,7 +32,7 @@
 __author__ = "Alfonso Tierno, Gerardo Garcia, Pablo Montes, xFlow Research, Igor D.C., Eduardo Sousa"
 __date__  = "$22-sep-2017 23:59:59$"
 
-import vimconn
+from osm_ro import vimconn
 # import json
 import logging
 import netaddr
@@ -45,7 +42,6 @@
 import re
 import copy
 from pprint import pformat
-from types import StringTypes
 
 from novaclient import client as nClient, exceptions as nvExceptions
 from keystoneauth1.identity import v2, v3
@@ -56,7 +52,7 @@
 from glanceclient import client as glClient
 import glanceclient.exc as gl1Exceptions
 from  cinderclient import client as cClient
-from httplib import HTTPException
+from http.client  import HTTPException   # TODO py3 check that this base exception matches python2 httplib.HTTPException
 from neutronclient.neutron import client as neClient
 from neutronclient.common import exceptions as neExceptions
 from requests.exceptions import ConnectionError
@@ -189,16 +185,15 @@
         simple representation of the data that cannot be converted back to
         python is returned.
         """
-        if isinstance(value, StringTypes):
+        if isinstance(value, str):
             return value
 
         try:
             return yaml.dump(value, Dumper=SafeDumper,
                              default_flow_style=True, width=256)
         except yaml.representer.RepresenterError:
-                self.logger.debug(
-                    'The following entity cannot be serialized in YAML:'
-                    '\n\n%s\n\n', pformat(value), exc_info=True)
+                self.logger.debug('The following entity cannot be serialized in YAML:\n\n%s\n\n', pformat(value),
+                                  exc_info=True)
                 return str(value)
 
     def _reload_connection(self):
@@ -399,11 +394,7 @@
     def _format_exception(self, exception):
         '''Transform a keystone, nova, neutron  exception into a vimconn exception'''
 
-        # Fixing bug 665 https://osm.etsi.org/bugzilla/show_bug.cgi?id=665
-        # There are some openstack versions that message error are unicode with non English
         message_error = exception.message
-        if isinstance(message_error, unicode):
-            message_error = message_error.encode("utf")
 
         if isinstance(exception, (neExceptions.NetworkNotFoundClient, nvExceptions.NotFound, ksExceptions.NotFound,
                                   gl1Exceptions.HTTPNotFound)):
@@ -1386,7 +1377,7 @@
                             if isinstance(floating_network['floating_ip'], str):
                                 if ip.get("floating_network_id") != floating_network['floating_ip']:
                                     continue
-                            free_floating_ip = ip.get("floating_ip_address")
+                            free_floating_ip = ip["id"]
                         else:
                             if isinstance(floating_network['floating_ip'], str) and \
                                 floating_network['floating_ip'].lower() != "true":
@@ -1412,15 +1403,17 @@
                             try:
                                 # self.logger.debug("Creating floating IP")
                                 new_floating_ip = self.neutron.create_floatingip(param)
-                                free_floating_ip = new_floating_ip['floatingip']['floating_ip_address']
+                                free_floating_ip = new_floating_ip['floatingip']['id']
                             except Exception as e:
                                 raise vimconn.vimconnException(type(e).__name__ + ": Cannot create new floating_ip " +
                                                                str(e), http_code=vimconn.HTTP_Conflict)
 
-                        fix_ip = floating_network.get('ip')
                         while not assigned:
                             try:
-                                server.add_floating_ip(free_floating_ip, fix_ip)
+                                # the vim_id key contains the neutron.port_id
+                                self.neutron.update_floatingip(free_floating_ip,
+                                                               {"floatingip": {"port_id": floating_network["vim_id"]}})
+                                # Using nove is deprecated on nova client 10.0
                                 assigned = True
                             except Exception as e:
                                 # openstack need some time after VM creation to asign an IP. So retry if fails
@@ -1435,7 +1428,7 @@
 
                 except Exception as e:
                     if not floating_network['exit_on_floating_ip_error']:
-                        self.logger.warn("Cannot create floating_ip. %s", str(e))
+                        self.logger.warning("Cannot create floating_ip. %s", str(e))
                         continue
                     raise
 
@@ -1770,7 +1763,7 @@
         for vlanID_range in self.config.get('dataplane_net_vlan_range'):
             try:
                 start_vlanid , end_vlanid = map(int, vlanID_range.replace(" ", "").split("-"))
-                for vlanID in xrange(start_vlanid, end_vlanid + 1):
+                for vlanID in range(start_vlanid, end_vlanid + 1):
                     if vlanID not in used_vlanIDs:
                         return vlanID
             except Exception as exp:
@@ -1804,7 +1797,7 @@
         for vlanID_range in self.config.get('multisegment_vlan_range'):
             try:
                 start_vlanid , end_vlanid = map(int, vlanID_range.replace(" ", "").split("-"))
-                for vlanID in xrange(start_vlanid, end_vlanid + 1):
+                for vlanID in range(start_vlanid, end_vlanid + 1):
                     if vlanID not in used_vlanIDs:
                         return vlanID
             except Exception as exp:
@@ -1953,8 +1946,7 @@
         return error_value, error_text
 
     def new_classification(self, name, ctype, definition):
-        self.logger.debug(
-            'Adding a new (Traffic) Classification to VIM, named %s', name)
+        self.logger.debug('Adding a new (Traffic) Classification to VIM, named %s', name)
         try:
             new_class = None
             self._reload_connection()
@@ -2021,8 +2013,7 @@
             self._format_exception(e)
 
     def new_sfi(self, name, ingress_ports, egress_ports, sfc_encap=True):
-        self.logger.debug(
-            "Adding a new Service Function Instance to VIM, named '%s'", name)
+        self.logger.debug("Adding a new Service Function Instance to VIM, named '%s'", name)
         try:
             new_sfi = None
             self._reload_connection()
@@ -2057,13 +2048,11 @@
             self._format_exception(e)
 
     def get_sfi(self, sfi_id):
-        self.logger.debug(
-            'Getting Service Function Instance %s from VIM', sfi_id)
+        self.logger.debug('Getting Service Function Instance %s from VIM', sfi_id)
         filter_dict = {"id": sfi_id}
         sfi_list = self.get_sfi_list(filter_dict)
         if len(sfi_list) == 0:
-            raise vimconn.vimconnNotFoundException(
-                "Service Function Instance '{}' not found".format(sfi_id))
+            raise vimconn.vimconnNotFoundException("Service Function Instance '{}' not found".format(sfi_id))
         elif len(sfi_list) > 1:
             raise vimconn.vimconnConflictException(
                 'Found more than one Service Function Instance '
@@ -2072,8 +2061,7 @@
         return sfi
 
     def get_sfi_list(self, filter_dict={}):
-        self.logger.debug("Getting Service Function Instances from "
-                          "VIM filter: '%s'", str(filter_dict))
+        self.logger.debug("Getting Service Function Instances from VIM filter: '%s'", str(filter_dict))
         try:
             self._reload_connection()
             filter_dict_os = filter_dict.copy()
@@ -2100,8 +2088,7 @@
             self._format_exception(e)
 
     def new_sf(self, name, sfis, sfc_encap=True):
-        self.logger.debug("Adding a new Service Function to VIM, "
-                          "named '%s'", name)
+        self.logger.debug("Adding a new Service Function to VIM, named '%s'", name)
         try:
             new_sf = None
             self._reload_connection()
@@ -2172,8 +2159,7 @@
             self._format_exception(e)
 
     def new_sfp(self, name, classifications, sfs, sfc_encap=True, spi=None):
-        self.logger.debug("Adding a new Service Function Path to VIM, "
-                          "named '%s'", name)
+        self.logger.debug("Adding a new Service Function Path to VIM, named '%s'", name)
         try:
             new_sfp = None
             self._reload_connection()
@@ -2215,8 +2201,7 @@
         return sfp
 
     def get_sfp_list(self, filter_dict={}):
-        self.logger.debug("Getting Service Function Paths from VIM filter: "
-                          "'%s'", str(filter_dict))
+        self.logger.debug("Getting Service Function Paths from VIM filter: '%s'", str(filter_dict))
         try:
             self._reload_connection()
             filter_dict_os = filter_dict.copy()
@@ -2231,8 +2216,7 @@
             self._format_exception(e)
 
     def delete_sfp(self, sfp_id):
-        self.logger.debug(
-            "Deleting Service Function Path '%s' from VIM", sfp_id)
+        self.logger.debug("Deleting Service Function Path '%s' from VIM", sfp_id)
         try:
             self._reload_connection()
             self.neutron.delete_sfc_port_chain(sfp_id)
diff --git a/RO-VIM-openstack/requirements.txt b/RO-VIM-openstack/requirements.txt
new file mode 100644
index 0000000..9c7dd5c
--- /dev/null
+++ b/RO-VIM-openstack/requirements.txt
@@ -0,0 +1,26 @@
+##
+# 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.
+##
+
+PyYAML
+python-openstackclient
+python-neutronclient
+requests
+netaddr
+#TODO py3 networking-l2gw
+#TODO py3 python-novaclient
+#TODO py3 python-keystoneclient
+#TODO py3 python-glanceclient
+#TODO py3 python-cinderclient
+git+https://osm.etsi.org/gerrit/osm/RO.git#egg=osm-ro&subdirectory=RO
diff --git a/RO-VIM-openstack/setup.py b/RO-VIM-openstack/setup.py
new file mode 100644
index 0000000..1b3deba
--- /dev/null
+++ b/RO-VIM-openstack/setup.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+##
+# 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.
+##
+
+from setuptools import setup
+
+_name = "osm_rovim_openstack"
+
+README = """
+===========
+osm-rovim_openstack
+===========
+
+osm-ro pluging for openstack VIM
+"""
+
+setup(
+    name=_name,
+    description='OSM ro vim plugin for openstack',
+    long_description=README,
+    version_command=('git describe --match v* --tags --long --dirty', 'pep440-git-full'),
+    # version=VERSION,
+    # python_requires='>3.5.0',
+    author='ETSI OSM',
+    author_email='alfonso.tiernosepulveda@telefonica.com',
+    maintainer='Alfonso Tierno',
+    maintainer_email='alfonso.tiernosepulveda@telefonica.com',
+    url='https://osm.etsi.org/gitweb/?p=osm/RO.git;a=summary',
+    license='Apache 2.0',
+
+    packages=[_name],
+    include_package_data=True,
+    dependency_links=["git+https://osm.etsi.org/gerrit/osm/RO.git#egg=osm-ro"],
+    install_requires=[
+        "python-openstackclient", "python-neutronclient", 
+        "requests", "netaddr", "PyYAML",
+        "osm-ro", # TODO py3 "networking-l2gw"
+        # "python-novaclient", "python-keystoneclient", "python-glanceclient", "python-cinderclient",
+    ],
+    setup_requires=['setuptools-version-command'],
+    entry_points={
+        'osm_rovim.plugins': ['rovim_openstack = osm_rovim_openstack.vimconn_openstack'],
+    },
+)
diff --git a/RO-VIM-openstack/stdeb.cfg b/RO-VIM-openstack/stdeb.cfg
new file mode 100644
index 0000000..ef5f94d
--- /dev/null
+++ b/RO-VIM-openstack/stdeb.cfg
@@ -0,0 +1,20 @@
+#
+# 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.
+#
+
+[DEFAULT]
+X-Python3-Version : >= 3.5
+Depends3: python3-openstackclient, python3-neutronclient, python3-requests, python3-netaddr, python3-yaml,
+          python3-osm-ro, python3-pip
+          # TODO py3 python3-networking-l2gw
diff --git a/RO-VIM-openstack/tox.ini b/RO-VIM-openstack/tox.ini
new file mode 100644
index 0000000..2a67756
--- /dev/null
+++ b/RO-VIM-openstack/tox.ini
@@ -0,0 +1,41 @@
+##
+# 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.
+##
+
+[tox]
+envlist = py3
+toxworkdir={homedir}/.tox
+
+[testenv]
+basepython = python3
+install_command = python3 -m pip install -r requirements.txt -U {opts} {packages}
+# deps = -r{toxinidir}/test-requirements.txt
+commands=python3 -m unittest discover -v
+
+[testenv:flake8]
+basepython = python3
+deps = flake8
+commands = flake8 osm_rovim_openstack --max-line-length 120 \
+    --exclude .svn,CVS,.gz,.git,__pycache__,.tox,local,temp --ignore W291,W293,E226,W504
+
+[testenv:unittest]
+basepython = python3
+commands = python3 -m unittest osm_rovim_openstack.tests
+
+[testenv:build]
+basepython = python3
+deps = stdeb
+       setuptools-version-command
+commands = python3 setup.py --command-packages=stdeb.command bdist_deb
+
diff --git a/RO-VIM-openvim/Makefile b/RO-VIM-openvim/Makefile
new file mode 100644
index 0000000..8c68832
--- /dev/null
+++ b/RO-VIM-openvim/Makefile
@@ -0,0 +1,24 @@
+##
+# 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.
+##
+
+all: clean package
+
+clean:
+	rm -rf dist deb_dist osm_rovim_openvim-*.tar.gz osm_rovim_openvim.egg-info .eggs
+
+package:
+	python3 setup.py --command-packages=stdeb.command sdist_dsc
+	cd deb_dist/osm-rovim-openvim*/ && dpkg-buildpackage -rfakeroot -uc -us
+
diff --git a/osm_ro/vimconn_openvim.py b/RO-VIM-openvim/osm_rovim_openvim/vimconn_openvim.py
similarity index 92%
rename from osm_ro/vimconn_openvim.py
rename to RO-VIM-openvim/osm_rovim_openvim/vimconn_openvim.py
index 7d1deb4..9490485 100644
--- a/osm_ro/vimconn_openvim.py
+++ b/RO-VIM-openvim/osm_rovim_openvim/vimconn_openvim.py
@@ -27,16 +27,16 @@
 __author__="Alfonso Tierno, Gerardo Garcia"
 __date__ ="$26-aug-2014 11:09:29$"
 
-import vimconn
+from osm_ro import vimconn
 import requests
 import json
 import yaml
 import logging
 import math
-from openmano_schemas import id_schema, name_schema, nameshort_schema, description_schema, \
+from osm_ro.openmano_schemas import id_schema, name_schema, nameshort_schema, description_schema, \
                             vlan1000_schema, integer0_schema
 from jsonschema import validate as js_v, exceptions as js_e
-from urllib import quote
+from urllib.parse import quote
 
 '''contain the openvim virtual machine status to openmano status'''
 vmStatus2manoFormat={'ACTIVE':'ACTIVE',
@@ -323,6 +323,7 @@
     }
 }
 
+
 class vimconnector(vimconn.vimconnector):
     def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None,
                  log_level="DEBUG", config={}, persistent_info={}):
@@ -357,9 +358,9 @@
         try:
             tenant_list = vim_response.json()["tenants"]
             if len(tenant_list) == 0:
-                raise vimconn.vimconnNotFoundException("No tenant found for name '%s'" % str(self.tenant_name))
+                raise vimconn.vimconnNotFoundException("No tenant found for name '{}'".format(self.tenant_name))
             elif len(tenant_list) > 1:
-                raise vimconn.vimconnConflictException ("More that one tenant found for name '%s'" % str(self.tenant_name))
+                raise vimconn.vimconnConflictException ("More that one tenant found for name '{}'".format(self.tenant_name))
             self.tenant = tenant_list[0]["id"]
             return self.tenant
         except Exception as e:
@@ -381,7 +382,7 @@
             #print "Input data: ", str(client_data)
             return True, client_data
         except js_e.ValidationError as exc:
-            print "validate_in error, jsonschema exception ", exc.message, "at", exc.path
+            print("validate_in error, jsonschema exception ", exc.message, "at", exc.path)
             return False, ("validate_in error, jsonschema exception ", exc.message, "at", exc.path)
     
     def _remove_extra_items(self, data, schema):
@@ -391,13 +392,16 @@
                 a= self._remove_extra_items(d, schema['items'])
                 if a is not None: deleted.append(a)
         elif type(data) is dict:
+            to_delete = []
             for k in data.keys():
                 if 'properties' not in schema or k not in schema['properties'].keys():
-                    del data[k]
+                    to_delete.append(k)
                     deleted.append(k)
                 else:
                     a = self._remove_extra_items(data[k], schema['properties'][k])
                     if a is not None:  deleted.append({k:a})
+            for k in to_delete:
+                del data[k]
         if len(deleted) == 0: return None
         elif len(deleted) == 1: return deleted[0]
         else: return deleted
@@ -469,7 +473,7 @@
         '''
         filterquery=[]
         filterquery_text=''
-        for k,v in filter_dict.iteritems():
+        for k,v in filter_dict.items():
             filterquery.append(str(k)+'='+str(v))
         if len(filterquery)>0:
             filterquery_text='?'+ '&'.join(filterquery)
@@ -554,7 +558,7 @@
                 del filter_dict["tenant_id"]
             filterquery=[]
             filterquery_text=''
-            for k,v in filter_dict.iteritems():
+            for k,v in filter_dict.items():
                 filterquery.append(str(k)+'='+str(v))
             if len(filterquery)>0:
                 filterquery_text='?'+ '&'.join(filterquery)
@@ -638,7 +642,7 @@
                 if "cores" not in numa and "threads" not in numa and "paired-threads" not in numa:
                     numa["paired-threads"] = new_flavor_dict["vcpus"]
                 if "memory" not in numa:
-                    numa["memory"] = int(math.ceil(new_flavor_dict["ram"]/1024.0))
+                    numa["memory"] = int(math.ceil(new_flavor_dict["ram"] / 1024.0))
                 for iface in numa.get("interfaces", ()):
                     if not iface.get("bandwidth"):
                         iface["bandwidth"] = "1 Mbps"
@@ -704,7 +708,7 @@
             if image_dict.get('description'):
                 new_image_dict['description'] = image_dict['description']
             if image_dict.get('metadata'):
-                new_image_dict['metadata'] = yaml.load(image_dict['metadata'])
+                new_image_dict['metadata'] = yaml.load(image_dict['metadata'], Loader=yaml.SafeLoader)
             if image_dict.get('location'):
                 new_image_dict['path'] = image_dict['location']
             payload_req = json.dumps({"image":new_image_dict})
@@ -755,9 +759,9 @@
             #if r is not None: 
             #    self.logger.warn("Warning: remove extra items %s", str(r))
             if len(response['images'])==0:
-                raise vimconn.vimconnNotFoundException("Image not found at VIM with path '%s'", path)
+                raise vimconn.vimconnNotFoundException("Image not found at VIM with path '{}'".format(path))
             elif len(response['images'])>1:
-                raise vimconn.vimconnConflictException("More than one image found at VIM with path '%s'", path)
+                raise vimconn.vimconnConflictException("More than one image found at VIM with path '{}'".format(path))
             return response['images'][0]['id']
         except (requests.exceptions.RequestException, js_e.ValidationError) as e:
             self._format_request_exception(e)
@@ -777,7 +781,7 @@
             self._get_my_tenant()
             filterquery=[]
             filterquery_text=''
-            for k,v in filter_dict.iteritems():
+            for k,v in filter_dict.items():
                 filterquery.append(str(k)+'='+str(v))
             if len(filterquery)>0:
                 filterquery_text='?'+ '&'.join(filterquery)
@@ -799,14 +803,14 @@
             self._get_my_tenant()
         except Exception as e:
             return -vimconn.HTTP_Not_Found, str(e)
-        print "VIMConnector: Adding a new VM instance from JSON to VIM"
+        print("VIMConnector: Adding a new VM instance from JSON to VIM")
         payload_req = vm_data
         try:
             vim_response = requests.post(self.url+'/'+self.tenant+'/servers', headers = self.headers_req, data=payload_req)
         except requests.exceptions.RequestException as e:
-            print "new_vminstancefromJSON Exception: ", e.args
+            print( "new_vminstancefromJSON Exception: ", e.args)
             return -vimconn.HTTP_Not_Found, str(e.args[0])
-        print vim_response
+        # print vim_response
         #print vim_response.status_code
         if vim_response.status_code == 200:
             #print vim_response.json()
@@ -815,16 +819,17 @@
             #print http_content
             if res:
                 r = self._remove_extra_items(http_content, new_image_response_schema)
-                if r is not None: print "Warning: remove extra items ", r
+                if r is not None: print("Warning: remove extra items ", r)
                 #print http_content
                 vminstance_id = http_content['server']['id']
-                print "Tenant image id: ",vminstance_id
+                print( "Tenant image id: ",vminstance_id)
                 return vim_response.status_code,vminstance_id
             else: return -vimconn.HTTP_Bad_Request,http_content
         else:
             #print vim_response.text
             jsonerror = self._format_jsonerror(vim_response)
-            text = 'Error in VIM "%s": not possible to add new vm instance. HTTP Response: %d. Error: %s' % (self.url, vim_response.status_code, jsonerror)
+            text = 'Error in VIM "{}": not possible to add new vm instance. HTTP Response: {}. Error: {}'.format(
+                self.url, vim_response.status_code, jsonerror)
             #print text
             return -vim_response.status_code,text
 
@@ -1111,7 +1116,7 @@
         and append to the server_dict
         '''
         if type(server_dict) is not dict: 
-            print 'vimconnector.host_vim2gui() ERROR, param server_dict must be a dictionary'
+            print( 'vimconnector.host_vim2gui() ERROR, param server_dict must be a dictionary')
             return
         RAD={}
         occupation={}
@@ -1126,7 +1131,7 @@
             RAD_item['cpus']['cores'] = []
             RAD_item['cpus']['eligible_cores'] = []
             occupation_item['cores']=[]
-            for _ in range(0, len(numa['cores']) / 2):
+            for _ in range(0, len(numa['cores']) // 2):
                 RAD_item['cpus']['cores'].append( [] )
             for core in numa['cores']:
                 RAD_item['cpus']['cores'][core['core_id']].append(core['thread_id'])
@@ -1137,7 +1142,7 @@
             occupation_item['ports']={}
             for iface in numa['interfaces']:
                 RAD_item['ports'][ iface['pci'] ] = 'speed:'+str(iface['Mbps'])+'M'
-                occupation_item['ports'][ iface['pci'] ] = { 'occupied': str(100*iface['Mbps_consumed'] / iface['Mbps']) + "%" }
+                occupation_item['ports'][ iface['pci'] ] = { 'occupied': str(100*iface['Mbps_consumed'] // iface['Mbps']) + "%" }
                 
             RAD[ numa['numa_socket'] ] = RAD_item
             occupation[ numa['numa_socket'] ] = occupation_item
@@ -1151,20 +1156,20 @@
         try:
             vim_response = requests.get(url)
         except requests.exceptions.RequestException as e:
-            print "get_hosts_info Exception: ", e.args
+            print( "get_hosts_info Exception: ", e.args)
             return -vimconn.HTTP_Not_Found, str(e.args[0])
-        print "vim get", url, "response:",  vim_response.status_code, vim_response.json()
+        print("vim get", url, "response:",  vim_response.status_code, vim_response.json())
         #print vim_response.status_code
         #print json.dumps(vim_response.json(), indent=4)
         if vim_response.status_code != 200:
-            #TODO: get error
-            print 'vimconnector.get_hosts_info error getting host list %d %s' %(vim_response.status_code, vim_response.json())
+            # TODO: get error
+            print('vimconnector.get_hosts_info error getting host list {} {}'.format(vim_response.status_code, vim_response.json()))
             return -vim_response.status_code, "Error getting host list"
         
         res,hosts = self._format_in(vim_response, get_hosts_response_schema)
             
         if res==False:
-            print "vimconnector.get_hosts_info error parsing GET HOSTS vim response", hosts
+            print("vimconnector.get_hosts_info error parsing GET HOSTS vim response", hosts)
             return vimconn.HTTP_Internal_Server_Error, hosts
     #obtain hosts details
         hosts_dict={}
@@ -1173,15 +1178,15 @@
             try:
                 vim_response = requests.get(url)
             except requests.exceptions.RequestException as e:
-                print "get_hosts_info Exception: ", e.args
+                print( "get_hosts_info Exception: ", e.args)
                 return -vimconn.HTTP_Not_Found, str(e.args[0])
-            print "vim get", url, "response:",  vim_response.status_code, vim_response.json()
+            print("vim get", url, "response:",  vim_response.status_code, vim_response.json())
             if vim_response.status_code != 200:
-                print 'vimconnector.get_hosts_info error getting detailed host %d %s' %(vim_response.status_code, vim_response.json())
+                print('vimconnector.get_hosts_info error getting detailed host {} {}'.format(vim_response.status_code, vim_response.json()))
                 continue
             res,host_detail = self._format_in(vim_response, get_host_detail_response_schema)
             if res==False:
-                print "vimconnector.get_hosts_info error parsing GET HOSTS/%s vim response" % host['id'], host_detail
+                print ("vimconnector.get_hosts_info error parsing GET HOSTS/{} vim response {}".format(host['id']), host_detail)
                 continue
             #print 'host id '+host['id'], json.dumps(host_detail, indent=4)
             self.host_vim2gui(host_detail, hosts_dict)
@@ -1195,20 +1200,20 @@
         try:
             vim_response = requests.get(url)
         except requests.exceptions.RequestException as e:
-            print "get_hosts Exception: ", e.args
+            print("get_hosts Exception: ", e.args)
             return -vimconn.HTTP_Not_Found, str(e.args[0])
-        print "vim get", url, "response:",  vim_response.status_code, vim_response.json()
+        print("vim get", url, "response:",  vim_response.status_code, vim_response.json())
         #print vim_response.status_code
         #print json.dumps(vim_response.json(), indent=4)
         if vim_response.status_code != 200:
             #TODO: get error
-            print 'vimconnector.get_hosts error getting host list %d %s' %(vim_response.status_code, vim_response.json())
+            print('vimconnector.get_hosts error getting host list {} {}'.format(vim_response.status_code, vim_response.json()))
             return -vim_response.status_code, "Error getting host list"
         
         res,hosts = self._format_in(vim_response, get_hosts_response_schema)
             
         if res==False:
-            print "vimconnector.get_host error parsing GET HOSTS vim response", hosts
+            print("vimconnector.get_host error parsing GET HOSTS vim response", hosts)
             return vimconn.HTTP_Internal_Server_Error, hosts
     #obtain instances from hosts
         for host in hosts['hosts']:
@@ -1216,15 +1221,15 @@
             try:
                 vim_response = requests.get(url)
             except requests.exceptions.RequestException as e:
-                print "get_hosts Exception: ", e.args
+                print("get_hosts Exception: ", e.args)
                 return -vimconn.HTTP_Not_Found, str(e.args[0])
-            print "vim get", url, "response:",  vim_response.status_code, vim_response.json()
+            print("vim get", url, "response:",  vim_response.status_code, vim_response.json())
             if vim_response.status_code != 200:
-                print 'vimconnector.get_hosts error getting instances at host %d %s' %(vim_response.status_code, vim_response.json())
+                print('vimconnector.get_hosts error getting instances at host {} {}'.format(vim_response.status_code, vim_response.json()))
                 continue
             res,servers = self._format_in(vim_response, get_server_response_schema)
             if res==False:
-                print "vimconnector.get_host error parsing GET SERVERS/%s vim response" % host['id'], servers
+                print("vimconnector.get_host error parsing GET SERVERS/{} vim response {}".format(host['id']), servers)
                 continue
             #print 'host id '+host['id'], json.dumps(host_detail, indent=4)
             host['instances'] = servers['servers']
@@ -1236,14 +1241,14 @@
         try:
             vim_response = requests.get(url)
         except requests.exceptions.RequestException as e:
-            print "get_processor_rankings Exception: ", e.args
+            print("get_processor_rankings Exception: ", e.args)
             return -vimconn.HTTP_Not_Found, str(e.args[0])
-        print "vim get", url, "response:", vim_response.status_code, vim_response.json()
+        print("vim get", url, "response:", vim_response.status_code, vim_response.json())
         #print vim_response.status_code
         #print json.dumps(vim_response.json(), indent=4)
         if vim_response.status_code != 200:
             #TODO: get error
-            print 'vimconnector.get_processor_rankings error getting processor rankings %d %s' %(vim_response.status_code, vim_response.json())
+            print('vimconnector.get_processor_rankings error getting processor rankings {} {}'.format(vim_response.status_code, vim_response.json()))
             return -vim_response.status_code, "Error getting processor rankings"
         
         res,rankings = self._format_in(vim_response, get_processor_rankings_response_schema)
@@ -1274,14 +1279,14 @@
         '''Adds a external port to VIM'''
         '''Returns the port identifier'''
         #TODO change to logging exception code policies
-        print "VIMConnector: Adding a new external port"
+        print( "VIMConnector: Adding a new external port")
         payload_req = port_data
         try:
             vim_response = requests.post(self.url_admin+'/ports', headers = self.headers_req, data=payload_req)
         except requests.exceptions.RequestException as e:
             self.logger.error("new_external_port Exception: ", str(e))
             return -vimconn.HTTP_Not_Found, str(e.args[0])
-        print vim_response
+        print( vim_response)
         #print vim_response.status_code
         if vim_response.status_code == 200:
         #print vim_response.json()
@@ -1290,16 +1295,17 @@
         #print http_content
             if res:
                 r = self._remove_extra_items(http_content, new_port_response_schema)
-                if r is not None: print "Warning: remove extra items ", r
+                if r is not None: print("Warning: remove extra items ", r)
                 #print http_content
                 port_id = http_content['port']['id']
-                print "Port id: ",port_id
+                print("Port id: ",port_id)
                 return vim_response.status_code,port_id
             else: return -vimconn.HTTP_Bad_Request,http_content
         else:
             #print vim_response.text
             jsonerror = self._format_jsonerror(vim_response)
-            text = 'Error in VIM "%s": not possible to add new external port. HTTP Response: %d. Error: %s' % (self.url_admin, vim_response.status_code, jsonerror)
+            text = 'Error in VIM "{}": not possible to add new external port. HTTP Response: {}. Error: {}'.format(
+                self.url_admin, vim_response.status_code, jsonerror)
             #print text
             return -vim_response.status_code,text
         
@@ -1307,7 +1313,7 @@
         '''Adds a external network to VIM (shared)'''
         '''Returns the network identifier'''
         #TODO change to logging exception code policies
-        print "VIMConnector: Adding external shared network to VIM (type " + net_type + "): "+ net_name
+        print("VIMConnector: Adding external shared network to VIM (type " + net_type + "): "+ net_name)
         
         payload_req = '{"network":{"name": "' + net_name + '","shared":true,"type": "' + net_type + '"}}'
         try:
@@ -1315,7 +1321,7 @@
         except requests.exceptions.RequestException as e:
             self.logger.error( "new_external_network Exception: ", e.args)
             return -vimconn.HTTP_Not_Found, str(e.args[0])
-        print vim_response
+        print(vim_response)
         #print vim_response.status_code
         if vim_response.status_code == 200:
             #print vim_response.json()
@@ -1324,16 +1330,17 @@
             #print http_content
             if res:
                 r = self._remove_extra_items(http_content, new_network_response_schema)
-                if r is not None: print "Warning: remove extra items ", r
+                if r is not None: print("Warning: remove extra items ", r)
                 #print http_content
                 network_id = http_content['network']['id']
-                print "Network id: ",network_id
+                print( "Network id: ",network_id)
                 return vim_response.status_code,network_id
             else: return -vimconn.HTTP_Bad_Request,http_content
         else:
             #print vim_response.text
             jsonerror = self._format_jsonerror(vim_response)
-            text = 'Error in VIM "%s": not possible to add new external network. HTTP Response: %d. Error: %s' % (self.url, vim_response.status_code, jsonerror)
+            text = 'Error in VIM "{}": not possible to add new external network. HTTP Response: {}. Error: {}'.format(
+                self.url, vim_response.status_code, jsonerror)
             #print text
             return -vim_response.status_code,text
         
@@ -1341,7 +1348,7 @@
         '''Connects a external port to a network'''
         '''Returns status code of the VIM response'''
         #TODO change to logging exception code policies
-        print "VIMConnector: Connecting external port to network"
+        print("VIMConnector: Connecting external port to network")
         
         payload_req = '{"port":{"network_id":"' + network_id + '"}}'
         if admin:
@@ -1353,9 +1360,9 @@
         try:
             vim_response = requests.put(url +'/ports/'+port_id, headers = self.headers_req, data=payload_req)
         except requests.exceptions.RequestException as e:
-            print "connect_port_network Exception: ", e.args
+            print("connect_port_network Exception: ", e.args)
             return -vimconn.HTTP_Not_Found, str(e.args[0])
-        print vim_response
+        print(vim_response)
         #print vim_response.status_code
         if vim_response.status_code == 200:
             #print vim_response.json()
@@ -1364,17 +1371,18 @@
             #print http_content
             if res:
                 r = self._remove_extra_items(http_content, new_port_response_schema)
-                if r is not None: print "Warning: remove extra items ", r
+                if r is not None: print("Warning: remove extra items ", r)
                 #print http_content
                 port_id = http_content['port']['id']
-                print "Port id: ",port_id
+                print("Port id: ",port_id)
                 return vim_response.status_code,port_id
             else: return -vimconn.HTTP_Bad_Request,http_content
         else:
-            print vim_response.text
+            print(vim_response.text)
             jsonerror = self._format_jsonerror(vim_response)
-            text = 'Error in VIM "%s": not possible to connect external port to network. HTTP Response: %d. Error: %s' % (self.url_admin, vim_response.status_code, jsonerror)
-            print text
+            text = 'Error in VIM "{}": not possible to connect external port to network. HTTP Response: {}.' \
+                   ' Error: {}'.format(self.url_admin, vim_response.status_code, jsonerror)
+            print(text)
             return -vim_response.status_code,text
         
 
diff --git a/RO-VIM-openvim/requirements.txt b/RO-VIM-openvim/requirements.txt
new file mode 100644
index 0000000..34a2518
--- /dev/null
+++ b/RO-VIM-openvim/requirements.txt
@@ -0,0 +1,19 @@
+##
+# 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.
+##
+
+PyYAML
+requests
+netaddr
+git+https://osm.etsi.org/gerrit/osm/RO.git#egg=osm-ro&subdirectory=RO
diff --git a/RO-VIM-openvim/setup.py b/RO-VIM-openvim/setup.py
new file mode 100644
index 0000000..19ac0ba
--- /dev/null
+++ b/RO-VIM-openvim/setup.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+##
+# 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.
+##
+
+from setuptools import setup
+
+_name = "osm_rovim_openvim"
+
+README = """
+===========
+osm-rovim_openvim
+===========
+
+osm-ro pluging for openvim VIM
+"""
+
+setup(
+    name=_name,
+    description='OSM ro vim plugin for openvim',
+    long_description=README,
+    version_command=('git describe --match v* --tags --long --dirty', 'pep440-git-full'),
+    # version=VERSION,
+    # python_requires='>3.5.0',
+    author='ETSI OSM',
+    author_email='alfonso.tiernosepulveda@telefonica.com',
+    maintainer='Alfonso Tierno',
+    maintainer_email='alfonso.tiernosepulveda@telefonica.com',
+    url='https://osm.etsi.org/gitweb/?p=osm/RO.git;a=summary',
+    license='Apache 2.0',
+
+    packages=[_name],
+    include_package_data=True,
+    dependency_links=["git+https://osm.etsi.org/gerrit/osm/RO.git#egg=osm-ro"],
+    install_requires=[
+        "requests", "netaddr", "PyYAML",
+    ],
+    setup_requires=['setuptools-version-command'],
+    entry_points={
+        'osm_rovim.plugins': ['rovim_openvim = osm_rovim_openvim.vimconn_openvim'],
+    },
+)
diff --git a/RO-VIM-openvim/stdeb.cfg b/RO-VIM-openvim/stdeb.cfg
new file mode 100644
index 0000000..50f9821
--- /dev/null
+++ b/RO-VIM-openvim/stdeb.cfg
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+[DEFAULT]
+X-Python3-Version : >= 3.5
+Depends3: python3-requests, python3-netaddr, python3-yaml, python3-osm-ro
diff --git a/RO-VIM-openvim/tox.ini b/RO-VIM-openvim/tox.ini
new file mode 100644
index 0000000..f17bf9a
--- /dev/null
+++ b/RO-VIM-openvim/tox.ini
@@ -0,0 +1,41 @@
+##
+# 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.
+##
+
+[tox]
+envlist = py3
+toxworkdir={homedir}/.tox
+
+[testenv]
+basepython = python3
+install_command = python3 -m pip install -r requirements.txt -U {opts} {packages}
+# deps = -r{toxinidir}/test-requirements.txt
+commands=python3 -m unittest discover -v
+
+[testenv:flake8]
+basepython = python3
+deps = flake8
+commands = flake8 osm_rovim_openvim --max-line-length 120 \
+    --exclude .svn,CVS,.gz,.git,__pycache__,.tox,local,temp --ignore W291,W293,E226,W504
+
+[testenv:unittest]
+basepython = python3
+commands = python3 -m unittest osm_rovim_openvim.tests
+
+[testenv:build]
+basepython = python3
+deps = stdeb
+       setuptools-version-command
+commands = python3 setup.py --command-packages=stdeb.command bdist_deb
+
diff --git a/RO-VIM-vmware/Makefile b/RO-VIM-vmware/Makefile
new file mode 100644
index 0000000..283afdf
--- /dev/null
+++ b/RO-VIM-vmware/Makefile
@@ -0,0 +1,26 @@
+##
+# Copyright VMware 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.
+##
+
+all: clean package
+
+clean:
+	rm -rf dist deb_dist osm_rovim_vmware-*.tar.gz osm_rovim_vmware.egg-info .eggs
+
+package:
+	python3 setup.py --command-packages=stdeb.command sdist_dsc
+	cp debian/python3-osm-rovim-vmware.postinst deb_dist/osm-rovim-vmware*/debian/
+	cd deb_dist/osm-rovim-vmware*/ && dpkg-buildpackage -rfakeroot -uc -us
+
diff --git a/RO-VIM-vmware/debian/python3-osm-rovim-vmware.postinst b/RO-VIM-vmware/debian/python3-osm-rovim-vmware.postinst
new file mode 100755
index 0000000..e7ce877
--- /dev/null
+++ b/RO-VIM-vmware/debian/python3-osm-rovim-vmware.postinst
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+##
+# Copyright VMware 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: OSM_TECH@list.etsi.org
+##
+
+echo "POST INSTALL OSM-ROVIM-VMWARE"
+
+#Pip packages required for vmware connector
+python3 -m pip install --upgrade pip
+python3 -m pip install --upgrade pyvcloud==19.1.1
+python3 -m pip install --upgrade progressbar
+python3 -m pip install --upgrade pyvmomi
+# python3 -m pip install --upgrade prettytable
+# python3 -m pip install --upgrade pyang pyangbind
diff --git a/osm_ro/tests/test_vimconn_vmware.py b/RO-VIM-vmware/osm_rovim_vmware/tests/test_vimconn_vmware.py
similarity index 99%
rename from osm_ro/tests/test_vimconn_vmware.py
rename to RO-VIM-vmware/osm_rovim_vmware/tests/test_vimconn_vmware.py
index 89ca36c..2075ac6 100755
--- a/osm_ro/tests/test_vimconn_vmware.py
+++ b/RO-VIM-vmware/osm_rovim_vmware/tests/test_vimconn_vmware.py
@@ -22,8 +22,8 @@
 ##
 
 
-from osm_ro.vimconn_vmware import vimconnector
-from osm_ro.vimconn import vimconnUnexpectedResponse,vimconnNotFoundException,vimconnException
+from osm_rovim_vmware.vimconn_vmware import vimconnector
+from osm_ro.vimconn import vimconnUnexpectedResponse, vimconnNotFoundException,vimconnException
 from pyvcloud.vcd.client import Client
 from lxml import etree as lxmlElementTree
 from pyvcloud.vcd.org import Org
@@ -31,7 +31,7 @@
 from pyvcloud.vcd.vapp import VApp
 import os
 import unittest
-import mock
+from unittest import mock
 import test_vimconn_vmware_xml_response as xml_resp
 from os import path
 
@@ -177,7 +177,7 @@
         result = self.vim.new_network(net_name, net_type)
 
         # assert verified expected and return result from VIM connector
-        self.assertEqual(result, 'df1956fa-da04-419e-a6a2-427b6f83788f')
+        self.assertEqual(result, ('df1956fa-da04-419e-a6a2-427b6f83788f', {}))
 
     @mock.patch.object(vimconnector, 'create_network_rest')
     def test_new_network_not_created(self, create_network_rest):
diff --git a/osm_ro/tests/test_vimconn_vmware_xml_response.py b/RO-VIM-vmware/osm_rovim_vmware/tests/test_vimconn_vmware_xml_response.py
similarity index 77%
rename from osm_ro/tests/test_vimconn_vmware_xml_response.py
rename to RO-VIM-vmware/osm_rovim_vmware/tests/test_vimconn_vmware_xml_response.py
index 968cb1f..334e423 100644
--- a/osm_ro/tests/test_vimconn_vmware_xml_response.py
+++ b/RO-VIM-vmware/osm_rovim_vmware/tests/test_vimconn_vmware_xml_response.py
@@ -21,7 +21,7 @@
 # contact:  osslegalrouting@vmware.com

 ##

 

-vdc_xml_response = """<?xml version="1.0" encoding="UTF-8"?>

+vdc_xml_response = """<?xml version="1.0" ?>

         <Vdc xmlns="http://www.vmware.com/vcloud/v1.5" status="1" name="Org3-VDC-PVDC1" id="urn:vcloud:vdc:2584137f-6541-4c04-a2a2-e56bfca14c69" href="https://localhost/api/vdc/2584137f-6541-4c04-a2a2-e56bfca14c69" type="application/vnd.vmware.vcloud.vdc+xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/vcloud/v1.5 http://localhost/api/v1.5/schema/master.xsd">

 		<Link rel="up" href="https://localhost/api/org/2cb3dffb-5c51-4355-8406-28553ead28ac" type="application/vnd.vmware.vcloud.org+xml"/>

 		<Link rel="down" href="https://localhost/api/vdc/2584137f-6541-4c04-a2a2-e56bfca14c69/metadata" type="application/vnd.vmware.vcloud.metadata+xml"/>

@@ -98,7 +98,7 @@
         <VCpuInMhz2>1000</VCpuInMhz2>

         </Vdc>"""

 

-network_xml_response = """<?xml version="1.0" encoding="UTF-8"?>

+network_xml_response = """<?xml version="1.0" ?>

              <OrgVdcNetwork xmlns="http://www.vmware.com/vcloud/v1.5" status="1" name="testing_6XXftDTroat1-03b18565-de01-4154-af51-8dbea42f0d84" id="urn:vcloud:network:5c04dc6d-6096-47c6-b72b-68f19013d491" href="https://localhost/api/network/5c04dc6d-6096-47c6-b72b-68f19013d491" type="application/vnd.vmware.vcloud.orgVdcNetwork+xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/vcloud/v1.5 http://localhost/api/v1.5/schema/master.xsd">

              <Link rel="up" href="https://localhost/api/vdc/2584137f-6541-4c04-a2a2-e56bfca14c69" type="application/vnd.vmware.vcloud.vdc+xml"/>

              <Link rel="down" href="https://localhost/api/network/5c04dc6d-6096-47c6-b72b-68f19013d491/metadata" type="application/vnd.vmware.vcloud.metadata+xml"/>

@@ -127,7 +127,7 @@
              <IsShared>false</IsShared>

              </OrgVdcNetwork>"""

 

-delete_network_xml_response = """<?xml version="1.0" encoding="UTF-8"?>

+delete_network_xml_response = """<?xml version="1.0" ?>

             <OrgVdcNetwork xmlns="http://www.vmware.com/vcloud/v1.5" status="1" name="testing_negjXxdlB-7fdcf9f3-de32-4ae6-b9f9-fb725a80a74f" id="urn:vcloud:network:0a55e5d1-43a2-4688-bc92-cb304046bf87" href="https://localhost/api/network/0a55e5d1-43a2-4688-bc92-cb304046bf87" type="application/vnd.vmware.vcloud.orgVdcNetwork+xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/vcloud/v1.5 http://localhost/api/v1.5/schema/master.xsd">

 			<Link rel="up" href="https://localhost/api/vdc/2584137f-6541-4c04-a2a2-e56bfca14c69" type="application/vnd.vmware.vcloud.vdc+xml"/>

 			<Link rel="down" href="https://localhost/api/network/0a55e5d1-43a2-4688-bc92-cb304046bf87/metadata" type="application/vnd.vmware.vcloud.metadata+xml"/>

@@ -154,7 +154,7 @@
 			<IsShared>false</IsShared>

 			</OrgVdcNetwork>"""

 

-create_network_xml_response = """<?xml version="1.0" encoding="UTF-8"?>

+create_network_xml_response = """<?xml version="1.0" ?>

             <OrgVdcNetwork xmlns="http://www.vmware.com/vcloud/v1.5" name="Test_network-25cb63aa-30e9-4de5-be76-1d6e00a2781a" id="urn:vcloud:network:df1956fa-da04-419e-a6a2-427b6f83788f" href="https://localhost/api/admin/network/df1956fa-da04-419e-a6a2-427b6f83788f" type="application/vnd.vmware.vcloud.orgVdcNetwork+xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/vcloud/v1.5 http://localhost/api/v1.5/schema/master.xsd">

             <Link rel="edit" href="https://localhost/api/admin/network/df1956fa-da04-419e-a6a2-427b6f83788f" type="application/vnd.vmware.vcloud.orgVdcNetwork+xml"/>

             <Link rel="remove" href="https://localhost/api/admin/network/df1956fa-da04-419e-a6a2-427b6f83788f"/>

@@ -189,7 +189,7 @@
             </Configuration><IsShared>false</IsShared>

             </OrgVdcNetwork>"""

 

-catalog1_xml_response = """<?xml version="1.0" encoding="UTF-8"?>

+catalog1_xml_response = """<?xml version="1.0" ?>

 <Catalog xmlns="http://www.vmware.com/vcloud/v1.5" name="Ubuntu-vm" id="urn:vcloud:catalog:d0a11b12-780e-4681-babb-2b1fd6693f62" href="https://localhost/api/catalog/d0a11b12-780e-4681-babb-2b1fd6693f62" type="application/vnd.vmware.vcloud.catalog+xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/vcloud/v1.5 http://localhost/api/v1.5/schema/master.xsd">

 <Link rel="up" href="https://localhost/api/org/2cb3dffb-5c51-4355-8406-28553ead28ac" type="application/vnd.vmware.vcloud.org+xml"/>

 <Link rel="down" href="https://localhost/api/catalog/d0a11b12-780e-4681-babb-2b1fd6693f62/metadata" type="application/vnd.vmware.vcloud.metadata+xml"/>

@@ -204,7 +204,7 @@
 <CatalogItems><CatalogItem href="https://localhost/api/catalogItem/04fc0041-8e40-4e37-b072-7dba3e1c6a30" id="04fc0041-8e40-4e37-b072-7dba3e1c6a30" name="Ubuntu-vm" type="application/vnd.vmware.vcloud.catalogItem+xml"/></CatalogItems><IsPublished>false</IsPublished><DateCreated>2017-03-17T03:17:11.293-07:00</DateCreated><VersionNumber>5</VersionNumber>

 </Catalog>"""

 

-catalog2_xml_response = """<?xml version="1.0" encoding="UTF-8"?>

+catalog2_xml_response = """<?xml version="1.0" ?>

 <Catalog xmlns="http://www.vmware.com/vcloud/v1.5" name="cirros" id="urn:vcloud:catalog:32ccb082-4a65-41f6-bcd6-38942e8a3829" href="https://localhost/api/catalog/32ccb082-4a65-41f6-bcd6-38942e8a3829" type="application/vnd.vmware.vcloud.catalog+xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/vcloud/v1.5 http://localhost/api/v1.5/schema/master.xsd">

 <Link rel="up" href="https://localhost/api/org/2cb3dffb-5c51-4355-8406-28553ead28ac" type="application/vnd.vmware.vcloud.org+xml"/>

 <Link rel="down" href="https://localhost/api/catalog/32ccb082-4a65-41f6-bcd6-38942e8a3829/metadata" type="application/vnd.vmware.vcloud.metadata+xml"/>

@@ -219,7 +219,7 @@
 <CatalogItems><CatalogItem href="https://localhost/api/catalogItem/98316d41-e38c-40c2-ac28-5462e8aada8c" id="98316d41-e38c-40c2-ac28-5462e8aada8c" name="cirros" type="application/vnd.vmware.vcloud.catalogItem+xml"/></CatalogItems><IsPublished>false</IsPublished><DateCreated>2017-03-08T02:06:07.003-08:00</DateCreated><VersionNumber>5</VersionNumber>

 </Catalog>"""

 

-vapp_xml_response = """<?xml version="1.0" encoding="UTF-8"?>

+vapp_xml_response = """<?xml version="1.0" ?>

 <VApp xmlns="http://www.vmware.com/vcloud/v1.5" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1" xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData" xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData" xmlns:vmw="http://www.vmware.com/schema/ovf" xmlns:ovfenv="http://schemas.dmtf.org/ovf/environment/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ovfDescriptorUploaded="true" deployed="true" status="4" name="Test1_vm-69a18104-8413-4cb8-bad7-b5afaec6f9fa" id="urn:vcloud:vapp:4f6a9b49-e92d-4935-87a1-0e4dc9c3a069" href="https://localhost/api/vApp/vapp-4f6a9b49-e92d-4935-87a1-0e4dc9c3a069" type="application/vnd.vmware.vcloud.vApp+xml" xsi:schemaLocation="http://schemas.dmtf.org/ovf/envelope/1 http://schemas.dmtf.org/ovf/envelope/1/dsp8023_1.1.0.xsd http://www.vmware.com/vcloud/v1.5 http://localhost/api/v1.5/schema/master.xsd http://www.vmware.com/schema/ovf http://www.vmware.com/schema/ovf http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2.22.0/CIM_ResourceAllocationSettingData.xsd http://schemas.dmtf.org/ovf/environment/1 http://schemas.dmtf.org/ovf/envelope/1/dsp8027_1.1.0.xsd http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2.22.0/CIM_VirtualSystemSettingData.xsd">

 <Link rel="power:powerOff" href="https://localhost/api/vApp/vapp-4f6a9b49-e92d-4935-87a1-0e4dc9c3a069/power/action/powerOff"/>

 <Link rel="power:reboot" href="https://localhost/api/vApp/vapp-4f6a9b49-e92d-4935-87a1-0e4dc9c3a069/power/action/reboot"/>

@@ -292,7 +292,7 @@
 <Link rel="down" href="https://localhost/api/vApp/vm-47d12505-5968-4e16-95a7-18743edb0c8b/virtualHardwareSection/disks" type="application/vnd.vmware.vcloud.rasdItemsList+xml"/>

 <Link rel="edit" href="https://localhost/api/vApp/vm-47d12505-5968-4e16-95a7-18743edb0c8b/virtualHardwareSection/disks" type="application/vnd.vmware.vcloud.rasdItemsList+xml"/><Link rel="down" href="https://localhost/api/vApp/vm-47d12505-5968-4e16-95a7-18743edb0c8b/virtualHardwareSection/media" type="application/vnd.vmware.vcloud.rasdItemsList+xml"/><Link rel="down" href="https://localhost/api/vApp/vm-47d12505-5968-4e16-95a7-18743edb0c8b/virtualHardwareSection/networkCards" type="application/vnd.vmware.vcloud.rasdItemsList+xml"/><Link rel="edit" href="https://localhost/api/vApp/vm-47d12505-5968-4e16-95a7-18743edb0c8b/virtualHardwareSection/networkCards" type="application/vnd.vmware.vcloud.rasdItemsList+xml"/><Link rel="down" href="https://localhost/api/vApp/vm-47d12505-5968-4e16-95a7-18743edb0c8b/virtualHardwareSection/serialPorts" type="application/vnd.vmware.vcloud.rasdItemsList+xml"/><Link rel="edit" href="https://localhost/api/vApp/vm-47d12505-5968-4e16-95a7-18743edb0c8b/virtualHardwareSection/serialPorts" type="application/vnd.vmware.vcloud.rasdItemsList+xml"/></ovf:VirtualHardwareSection><ovf:OperatingSystemSection xmlns:vcloud="http://www.vmware.com/vcloud/v1.5" ovf:id="94" vcloud:type="application/vnd.vmware.vcloud.operatingSystemSection+xml" vmw:osType="ubuntu64Guest" vcloud:href="https://localhost/api/vApp/vm-47d12505-5968-4e16-95a7-18743edb0c8b/operatingSystemSection/"><ovf:Info>Specifies the operating system installed</ovf:Info><ovf:Description>Ubuntu Linux (64-bit)</ovf:Description><Link rel="edit" href="https://localhost/api/vApp/vm-47d12505-5968-4e16-95a7-18743edb0c8b/operatingSystemSection/" type="application/vnd.vmware.vcloud.operatingSystemSection+xml"/></ovf:OperatingSystemSection><NetworkConnectionSection href="https://localhost/api/vApp/vm-47d12505-5968-4e16-95a7-18743edb0c8b/networkConnectionSection/" type="application/vnd.vmware.vcloud.networkConnectionSection+xml" ovf:required="false"><ovf:Info>Specifies the available VM network connections</ovf:Info><PrimaryNetworkConnectionIndex>0</PrimaryNetworkConnectionIndex><NetworkConnection needsCustomization="false" network="testing_T6nODiW4-68f68d93-0350-4d86-b40b-6e74dedf994d">    <NetworkConnectionIndex>0</NetworkConnectionIndex>    <IpAddress>12.19.21.20</IpAddress>    <IsConnected>true</IsConnected>    <MACAddress>00:50:56:01:12:a2</MACAddress>    <IpAddressAllocationMode>DHCP</IpAddressAllocationMode></NetworkConnection><Link rel="edit" href="https://localhost/api/vApp/vm-47d12505-5968-4e16-95a7-18743edb0c8b/networkConnectionSection/" type="application/vnd.vmware.vcloud.networkConnectionSection+xml"/></NetworkConnectionSection><GuestCustomizationSection href="https://localhost/api/vApp/vm-47d12505-5968-4e16-95a7-18743edb0c8b/guestCustomizationSection/" type="application/vnd.vmware.vcloud.guestCustomizationSection+xml" ovf:required="false"><ovf:Info>Specifies Guest OS Customization Settings</ovf:Info><Enabled>true</Enabled><ChangeSid>false</ChangeSid><VirtualMachineId>47d12505-5968-4e16-95a7-18743edb0c8b</VirtualMachineId><JoinDomainEnabled>false</JoinDomainEnabled><UseOrgSettings>false</UseOrgSettings><AdminPasswordEnabled>false</AdminPasswordEnabled><AdminPasswordAuto>true</AdminPasswordAuto><AdminAutoLogonEnabled>false</AdminAutoLogonEnabled><AdminAutoLogonCount>0</AdminAutoLogonCount><ResetPasswordRequired>false</ResetPasswordRequired><ComputerName>Ubuntu-vm-001</ComputerName><Link rel="edit" href="https://localhost/api/vApp/vm-47d12505-5968-4e16-95a7-18743edb0c8b/guestCustomizationSection/" type="application/vnd.vmware.vcloud.guestCustomizationSection+xml"/></GuestCustomizationSection><RuntimeInfoSection xmlns:vcloud="http://www.vmware.com/vcloud/v1.5" vcloud:type="application/vnd.vmware.vcloud.virtualHardwareSection+xml" vcloud:href="https://localhost/api/vApp/vm-47d12505-5968-4e16-95a7-18743edb0c8b/runtimeInfoSection"><ovf:Info>Specifies Runtime info</ovf:Info><VMWareTools version="2147483647"/></RuntimeInfoSection><SnapshotSection href="https://localhost/api/vApp/vm-47d12505-5968-4e16-95a7-18743edb0c8b/snapshotSection" type="application/vnd.vmware.vcloud.snapshotSection+xml" ovf:required="false"><ovf:Info>Snapshot information section</ovf:Info></SnapshotSection><DateCreated>2017-09-21T01:15:53.863-07:00</DateCreated><VAppScopedLocalId>Ubuntu-vm</VAppScopedLocalId><ovfenv:Environment xmlns:ns11="http://www.vmware.com/schema/ovfenv" ovfenv:id="" ns11:vCenterId="vm-7833"><ovfenv:PlatformSection>    <ovfenv:Kind>VMware ESXi</ovfenv:Kind>    <ovfenv:Version>6.0.0</ovfenv:Version>    <ovfenv:Vendor>VMware, Inc.</ovfenv:Vendor>    <ovfenv:Locale>en</ovfenv:Locale></ovfenv:PlatformSection><ovfenv:PropertySection>    <ovfenv:Property ovfenv:key="vCloud_UseSysPrep" ovfenv:value="None"/>    <ovfenv:Property ovfenv:key="vCloud_bitMask" ovfenv:value="1"/>    <ovfenv:Property ovfenv:key="vCloud_bootproto_0" ovfenv:value="dhcp"/>    <ovfenv:Property ovfenv:key="vCloud_computerName" ovfenv:value="Ubuntu-vm-001"/>    <ovfenv:Property ovfenv:key="vCloud_macaddr_0" ovfenv:value="00:50:56:01:12:a2"/>    <ovfenv:Property ovfenv:key="vCloud_markerid" ovfenv:value="c743cbe8-136e-4cf8-9e42-b291646b8058"/>    <ovfenv:Property ovfenv:key="vCloud_numnics" ovfenv:value="1"/>    <ovfenv:Property ovfenv:key="vCloud_primaryNic" ovfenv:value="0"/>    <ovfenv:Property ovfenv:key="vCloud_reconfigToken" ovfenv:value="246124151"/>    <ovfenv:Property ovfenv:key="vCloud_resetPassword" ovfenv:value="0"/></ovfenv:PropertySection><ve:EthernetAdapterSection xmlns:ve="http://www.vmware.com/schema/ovfenv" xmlns="http://schemas.dmtf.org/ovf/environment/1" xmlns:oe="http://schemas.dmtf.org/ovf/environment/1">    <ve:Adapter ve:mac="00:50:56:01:12:a2" ve:network="DPG-MGMT-3151" ve:unitNumber="7"/></ve:EthernetAdapterSection></ovfenv:Environment><VmCapabilities href="https://localhost/api/vApp/vm-47d12505-5968-4e16-95a7-18743edb0c8b/vmCapabilities/" type="application/vnd.vmware.vcloud.vmCapabilitiesSection+xml"><Link rel="edit" href="https://localhost/api/vApp/vm-47d12505-5968-4e16-95a7-18743edb0c8b/vmCapabilities/" type="application/vnd.vmware.vcloud.vmCapabilitiesSection+xml"/><MemoryHotAddEnabled>false</MemoryHotAddEnabled><CpuHotAddEnabled>false</CpuHotAddEnabled></VmCapabilities><StorageProfile href="https://localhost/api/vdcStorageProfile/950701fb-2b8a-4808-80f1-27d1170a2bfc" name="*" type="application/vnd.vmware.vcloud.vdcStorageProfile+xml"/></Vm></Children></VApp>"""

 

-poweroff_task_xml = """<?xml version="1.0" encoding="UTF-8"?>

+poweroff_task_xml = """<?xml version="1.0" ?>

                 <Task xmlns="http://www.vmware.com/vcloud/v1.5" cancelRequested="false" expiryTime="2017-12-22T23:18:23.040-08:00" operation="Powering Off Virtual Application Test1_vm-f370dafc-4aad-4415-bad9-68509dda67c9(f26ebf0a-f675-4622-83a6-64c6401769ac)" operationName="vappPowerOff" serviceNamespace="com.vmware.vcloud" startTime="2017-09-23T23:18:23.040-07:00" status="queued" name="task" id="urn:vcloud:task:26975b6e-310e-4ed9-914e-ba7051eaabcb" href="https://localhost/api/task/26975b6e-310e-4ed9-914e-ba7051eaabcb" type="application/vnd.vmware.vcloud.task+xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/vcloud/v1.5 http://localhost/api/v1.5/schema/master.xsd">

 		<Owner href="https://localhost/api/vApp/vapp-f26ebf0a-f675-4622-83a6-64c6401769ac" name="Test1_vm-f370dafc-4aad-4415-bad9-68509dda67c9" type="application/vnd.vmware.vcloud.vApp+xml"/>

 		<User href="https://localhost/api/admin/user/f7b6beba-96db-4674-b187-675ed1873c8c" name="orgadmin" type="application/vnd.vmware.admin.user+xml"/>

@@ -376,7 +376,7 @@
 </Org>

 """

 

-delete_catalog_xml_response = """<?xml version="1.0" encoding="UTF-8"?>\n<Catalog xmlns="http://www.vmware.com/vcloud/v1.5" name="80d8488f67ba1de98b7f485fba6abbd2" id="urn:vcloud:catalog:f3bf3733-465b-419f-b675-52f91d18edbb" href="https://localhost/api/catalog/f3bf3733-465b-419f-b675-52f91d18edbb" type="application/vnd.vmware.vcloud.catalog+xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/vcloud/v1.5 http://localhost/api/v1.5/schema/master.xsd">

+delete_catalog_xml_response = """<?xml version="1.0" ?>\n<Catalog xmlns="http://www.vmware.com/vcloud/v1.5" name="80d8488f67ba1de98b7f485fba6abbd2" id="urn:vcloud:catalog:f3bf3733-465b-419f-b675-52f91d18edbb" href="https://localhost/api/catalog/f3bf3733-465b-419f-b675-52f91d18edbb" type="application/vnd.vmware.vcloud.catalog+xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/vcloud/v1.5 http://localhost/api/v1.5/schema/master.xsd">

 <Link rel="up" href="https://localhost/api/org/2cb3dffb-5c51-4355-8406-28553ead28ac" type="application/vnd.vmware.vcloud.org+xml"/>

 <Link rel="down" href="https://localhost/api/catalog/f3bf3733-465b-419f-b675-52f91d18edbb/metadata" type="application/vnd.vmware.vcloud.metadata+xml"/>

 <Link rel="add" href="https://localhost/api/catalog/f3bf3733-465b-419f-b675-52f91d18edbb/catalogItems" type="application/vnd.vmware.vcloud.catalogItem+xml"/>

@@ -398,7 +398,7 @@
 <VersionNumber>2</VersionNumber>

 </Catalog>"""

 

-delete_catalog_item_xml_response = """<?xml version="1.0" encoding="UTF-8"?>

+delete_catalog_item_xml_response = """<?xml version="1.0" ?>

 <CatalogItem xmlns="http://www.vmware.com/vcloud/v1.5" size="0" name="80d8488f67ba1de98b7f485fba6abbd2" id="urn:vcloud:catalogitem:8a984fdd-d2cb-4d58-a739-2ea12560aded" href="https://localhost/api/catalogItem/8a984fdd-d2cb-4d58-a739-2ea12560aded" type="application/vnd.vmware.vcloud.catalogItem+xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/vcloud/v1.5 http://localhost/api/v1.5/schema/master.xsd">

 <Link rel="up" href="https://localhost/api/catalog/f3bf3733-465b-419f-b675-52f91d18edbb" type="application/vnd.vmware.vcloud.catalog+xml"/>

 <Link rel="down" href="https://localhost/api/catalogItem/8a984fdd-d2cb-4d58-a739-2ea12560aded/metadata" type="application/vnd.vmware.vcloud.metadata+xml"/>

@@ -431,7 +431,7 @@
 </Task>

 """

 

-vm_xml_response = """<?xml version="1.0" encoding="UTF-8"?>

+vm_xml_response = """<?xml version="1.0" ?>

 <Vm xmlns="http://www.vmware.com/vcloud/v1.5" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1" xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData" xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData" xmlns:vmw="http://www.vmware.com/schema/ovf" xmlns:ovfenv="http://schemas.dmtf.org/ovf/environment/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" needsCustomization="false" nestedHypervisorEnabled="false" deployed="true" status="4" name="Ubuntu_no_nic" id="urn:vcloud:vm:53a529b2-10d8-4d56-a7ad-8182acdbe71c" href="https://localhost/api/vApp/vm-53a529b2-10d8-4d56-a7ad-8182acdbe71c" type="application/vnd.vmware.vcloud.vm+xml" xsi:schemaLocation="http://schemas.dmtf.org/ovf/envelope/1 http://schemas.dmtf.org/ovf/envelope/1/dsp8023_1.1.0.xsd http://www.vmware.com/vcloud/v1.5 http://localhost/api/v1.5/schema/master.xsd http://www.vmware.com/schema/ovf http://www.vmware.com/schema/ovf http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2.22.0/CIM_ResourceAllocationSettingData.xsd http://schemas.dmtf.org/ovf/environment/1 http://schemas.dmtf.org/ovf/envelope/1/dsp8027_1.1.0.xsd http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2.22.0/CIM_VirtualSystemSettingData.xsd">

 <Link rel="power:powerOff" href="https://localhost/api/vApp/vm-53a529b2-10d8-4d56-a7ad-8182acdbe71c/power/action/powerOff"/>

 <Link rel="power:reboot" href="https://localhost/api/vApp/vm-53a529b2-10d8-4d56-a7ad-8182acdbe71c/power/action/reboot"/>    <Link rel="power:reset" href="https://localhost/api/vApp/vm-53a529b2-10d8-4d56-a7ad-8182acdbe71c/power/action/reset"/>

@@ -626,12 +626,12 @@
     <StorageProfile href="https://localhost/api/vdcStorageProfile/950701fb-2b8a-4808-80f1-27d1170a2bfc" name="*" type="application/vnd.vmware.vcloud.vdcStorageProfile+xml"/>

 </Vm>"""

 

-delete_tenant = """<?xml version="1.0" encoding="UTF-8"?>\n<Vdc xmlns="http://www.vmware.com/vcloud/v1.5" xmlns:vmext="http://www.vmware.com/vcloud/extension/v1.5" status="1" name="testing_Cqm5fiZ" id="urn:vcloud:vdc:753227f5-d6c6-4478-9546-acc5cfff21e9" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9" type="application/vnd.vmware.vcloud.vdc+xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/vcloud/v1.5 http://localhost/api/v1.5/schema/master.xsd http://www.vmware.com/vcloud/extension/v1.5 http://localhost/api/v1.5/schema/vmwextensions.xsd">\n    <VCloudExtension required="false">\n        <vmext:VimObjectRef>\n            <vmext:VimServerRef href="https://localhost/api/admin/extension/vimServer/cc82baf9-9f80-4468-bfe9-ce42b3f9dde5" name="VC" type="application/vnd.vmware.admin.vmwvirtualcenter+xml"/>\n            <vmext:MoRef>resgroup-9025</vmext:MoRef>\n            <vmext:VimObjectType>RESOURCE_POOL</vmext:VimObjectType>\n        </vmext:VimObjectRef>\n    </VCloudExtension>\n    <Link rel="up" href="https://localhost/api/org/2cb3dffb-5c51-4355-8406-28553ead28ac" type="application/vnd.vmware.vcloud.org+xml"/>\n    <Link rel="down" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/metadata" type="application/vnd.vmware.vcloud.metadata+xml"/>\n    <Link rel="edit" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9" type="application/vnd.vmware.vcloud.vdc+xml"/>\n    <Link rel="remove" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9"/>\n    <Link rel="add" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/action/uploadVAppTemplate" type="application/vnd.vmware.vcloud.uploadVAppTemplateParams+xml"/>\n    <Link rel="add" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/media" type="application/vnd.vmware.vcloud.media+xml"/>\n    <Link rel="add" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/action/instantiateOvf" type="application/vnd.vmware.vcloud.instantiateOvfParams+xml"/>\n    <Link rel="add" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/action/instantiateVAppTemplate" type="application/vnd.vmware.vcloud.instantiateVAppTemplateParams+xml"/>\n    <Link rel="add" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/action/cloneVApp" type="application/vnd.vmware.vcloud.cloneVAppParams+xml"/>\n    <Link rel="add" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/action/cloneVAppTemplate" type="application/vnd.vmware.vcloud.cloneVAppTemplateParams+xml"/>\n    <Link rel="add" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/action/cloneMedia" type="application/vnd.vmware.vcloud.cloneMediaParams+xml"/>\n    <Link rel="add" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/action/captureVApp" type="application/vnd.vmware.vcloud.captureVAppParams+xml"/>\n    <Link rel="add" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/action/composeVApp" type="application/vnd.vmware.vcloud.composeVAppParams+xml"/>\n    <Link rel="add" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/disk" type="application/vnd.vmware.vcloud.diskCreateParams+xml"/>\n    <Link rel="edgeGateways" href="https://localhost/api/admin/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/edgeGateways" type="application/vnd.vmware.vcloud.query.records+xml"/>\n    <Link rel="add" href="https://localhost/api/admin/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/networks" type="application/vnd.vmware.vcloud.orgVdcNetwork+xml"/>\n    <Link rel="orgVdcNetworks" href="https://localhost/api/admin/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/networks" type="application/vnd.vmware.vcloud.query.records+xml"/>\n    <Link rel="alternate" href="https://localhost/api/admin/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9" type="application/vnd.vmware.admin.vdc+xml"/>\n    <Description>opnemano</Description>\n    <AllocationModel>AllocationVApp</AllocationModel>\n    <ComputeCapacity>\n        <Cpu>\n            <Units>MHz</Units>\n            <Allocated>0</Allocated>\n            <Limit>2048</Limit>\n            <Reserved>0</Reserved>\n            <Used>0</Used>\n            <Overhead>0</Overhead>\n        </Cpu>\n        <Memory>\n            <Units>MB</Units>\n            <Allocated>0</Allocated>\n            <Limit>2048</Limit>\n            <Reserved>0</Reserved>\n            <Used>0</Used>\n            <Overhead>0</Overhead>\n        </Memory>\n    </ComputeCapacity>\n    <ResourceEntities/>\n    <AvailableNetworks/>\n    <Capabilities>\n        <SupportedHardwareVersions>\n            <SupportedHardwareVersion>vmx-04</SupportedHardwareVersion>\n            <SupportedHardwareVersion>vmx-07</SupportedHardwareVersion>\n            <SupportedHardwareVersion>vmx-08</SupportedHardwareVersion>\n            <SupportedHardwareVersion>vmx-09</SupportedHardwareVersion>\n            <SupportedHardwareVersion>vmx-10</SupportedHardwareVersion>\n            <SupportedHardwareVersion>vmx-11</SupportedHardwareVersion>\n        </SupportedHardwareVersions>\n    </Capabilities>\n    <NicQuota>100</NicQuota>\n    <NetworkQuota>100</NetworkQuota>\n    <UsedNetworkCount>0</UsedNetworkCount>\n    <VmQuota>50</VmQuota>\n    <IsEnabled>true</IsEnabled>\n    <VdcStorageProfiles>\n        <VdcStorageProfile href="https://localhost/api/vdcStorageProfile/37ec8982-e6c3-4fba-a107-0fa36fe292d0" name="NFS Storage Policy" type="application/vnd.vmware.vcloud.vdcStorageProfile+xml"/>\n    </VdcStorageProfiles>\n    <VCpuInMhz2>1000</VCpuInMhz2>\n</Vdc>\n"""

+delete_tenant = """<?xml version="1.0" ?>\n<Vdc xmlns="http://www.vmware.com/vcloud/v1.5" xmlns:vmext="http://www.vmware.com/vcloud/extension/v1.5" status="1" name="testing_Cqm5fiZ" id="urn:vcloud:vdc:753227f5-d6c6-4478-9546-acc5cfff21e9" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9" type="application/vnd.vmware.vcloud.vdc+xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/vcloud/v1.5 http://localhost/api/v1.5/schema/master.xsd http://www.vmware.com/vcloud/extension/v1.5 http://localhost/api/v1.5/schema/vmwextensions.xsd">\n    <VCloudExtension required="false">\n        <vmext:VimObjectRef>\n            <vmext:VimServerRef href="https://localhost/api/admin/extension/vimServer/cc82baf9-9f80-4468-bfe9-ce42b3f9dde5" name="VC" type="application/vnd.vmware.admin.vmwvirtualcenter+xml"/>\n            <vmext:MoRef>resgroup-9025</vmext:MoRef>\n            <vmext:VimObjectType>RESOURCE_POOL</vmext:VimObjectType>\n        </vmext:VimObjectRef>\n    </VCloudExtension>\n    <Link rel="up" href="https://localhost/api/org/2cb3dffb-5c51-4355-8406-28553ead28ac" type="application/vnd.vmware.vcloud.org+xml"/>\n    <Link rel="down" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/metadata" type="application/vnd.vmware.vcloud.metadata+xml"/>\n    <Link rel="edit" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9" type="application/vnd.vmware.vcloud.vdc+xml"/>\n    <Link rel="remove" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9"/>\n    <Link rel="add" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/action/uploadVAppTemplate" type="application/vnd.vmware.vcloud.uploadVAppTemplateParams+xml"/>\n    <Link rel="add" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/media" type="application/vnd.vmware.vcloud.media+xml"/>\n    <Link rel="add" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/action/instantiateOvf" type="application/vnd.vmware.vcloud.instantiateOvfParams+xml"/>\n    <Link rel="add" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/action/instantiateVAppTemplate" type="application/vnd.vmware.vcloud.instantiateVAppTemplateParams+xml"/>\n    <Link rel="add" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/action/cloneVApp" type="application/vnd.vmware.vcloud.cloneVAppParams+xml"/>\n    <Link rel="add" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/action/cloneVAppTemplate" type="application/vnd.vmware.vcloud.cloneVAppTemplateParams+xml"/>\n    <Link rel="add" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/action/cloneMedia" type="application/vnd.vmware.vcloud.cloneMediaParams+xml"/>\n    <Link rel="add" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/action/captureVApp" type="application/vnd.vmware.vcloud.captureVAppParams+xml"/>\n    <Link rel="add" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/action/composeVApp" type="application/vnd.vmware.vcloud.composeVAppParams+xml"/>\n    <Link rel="add" href="https://localhost/api/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/disk" type="application/vnd.vmware.vcloud.diskCreateParams+xml"/>\n    <Link rel="edgeGateways" href="https://localhost/api/admin/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/edgeGateways" type="application/vnd.vmware.vcloud.query.records+xml"/>\n    <Link rel="add" href="https://localhost/api/admin/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/networks" type="application/vnd.vmware.vcloud.orgVdcNetwork+xml"/>\n    <Link rel="orgVdcNetworks" href="https://localhost/api/admin/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9/networks" type="application/vnd.vmware.vcloud.query.records+xml"/>\n    <Link rel="alternate" href="https://localhost/api/admin/vdc/753227f5-d6c6-4478-9546-acc5cfff21e9" type="application/vnd.vmware.admin.vdc+xml"/>\n    <Description>opnemano</Description>\n    <AllocationModel>AllocationVApp</AllocationModel>\n    <ComputeCapacity>\n        <Cpu>\n            <Units>MHz</Units>\n            <Allocated>0</Allocated>\n            <Limit>2048</Limit>\n            <Reserved>0</Reserved>\n            <Used>0</Used>\n            <Overhead>0</Overhead>\n        </Cpu>\n        <Memory>\n            <Units>MB</Units>\n            <Allocated>0</Allocated>\n            <Limit>2048</Limit>\n            <Reserved>0</Reserved>\n            <Used>0</Used>\n            <Overhead>0</Overhead>\n        </Memory>\n    </ComputeCapacity>\n    <ResourceEntities/>\n    <AvailableNetworks/>\n    <Capabilities>\n        <SupportedHardwareVersions>\n            <SupportedHardwareVersion>vmx-04</SupportedHardwareVersion>\n            <SupportedHardwareVersion>vmx-07</SupportedHardwareVersion>\n            <SupportedHardwareVersion>vmx-08</SupportedHardwareVersion>\n            <SupportedHardwareVersion>vmx-09</SupportedHardwareVersion>\n            <SupportedHardwareVersion>vmx-10</SupportedHardwareVersion>\n            <SupportedHardwareVersion>vmx-11</SupportedHardwareVersion>\n        </SupportedHardwareVersions>\n    </Capabilities>\n    <NicQuota>100</NicQuota>\n    <NetworkQuota>100</NetworkQuota>\n    <UsedNetworkCount>0</UsedNetworkCount>\n    <VmQuota>50</VmQuota>\n    <IsEnabled>true</IsEnabled>\n    <VdcStorageProfiles>\n        <VdcStorageProfile href="https://localhost/api/vdcStorageProfile/37ec8982-e6c3-4fba-a107-0fa36fe292d0" name="NFS Storage Policy" type="application/vnd.vmware.vcloud.vdcStorageProfile+xml"/>\n    </VdcStorageProfiles>\n    <VCpuInMhz2>1000</VCpuInMhz2>\n</Vdc>\n"""

 

 catalog_list_xml = """<CatalogItem xmlns="http://www.vmware.com/vcloud/v1.5" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" size="0" name="Ubuntu_no_nic" id="urn:vcloud:catalogitem:d79fb542-6ad4-4c09-8cfc-f6104cbf67ad" href="https://localhost/api/catalogItem/d79fb542-6ad4-4c09-8cfc-f6104cbf67ad" type="application/vnd.vmware.vcloud.catalogItem+xml" xsi:schemaLocation="http://www.vmware.com/vcloud/v1.5 http://localhost/api/v1.5/schema/master.xsd"><Link rel="up" href="https://localhost/api/catalog/e8d953db-8dc9-46d5-9cab-329774cd2ad9" type="application/vnd.vmware.vcloud.catalog+xml"/><Link rel="down" href="https://localhost/api/catalogItem/d79fb542-6ad4-4c09-8cfc-f6104cbf67ad/metadata" type="application/vnd.vmware.vcloud.metadata+xml"/><Link rel="edit" href="https://localhost/api/catalogItem/d79fb542-6ad4-4c09-8cfc-f6104cbf67ad" type="application/vnd.vmware.vcloud.catalogItem+xml"/><Link rel="remove" href="https://localhost/api/catalogItem/d79fb542-6ad4-4c09-8cfc-f6104cbf67ad"/><Description/><Entity href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435" name="Ubuntu_no_nic" type="application/vnd.vmware.vcloud.vAppTemplate+xml"/><DateCreated>2017-10-14T23:52:58.097-07:00</DateCreated><VersionNumber>1</VersionNumber></CatalogItem>"""

 

-catalogItem_xml = """<?xml version="1.0" encoding="UTF-8"?>\n<CatalogItem xmlns="http://www.vmware.com/vcloud/v1.5" size="0" name="Ubuntu_no_nic" id="urn:vcloud:catalogitem:d79fb542-6ad4-4c09-8cfc-f6104cbf67ad" href="https://localhost/api/catalogItem/d79fb542-6ad4-4c09-8cfc-f6104cbf67ad" type="application/vnd.vmware.vcloud.catalogItem+xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/vcloud/v1.5 http://localhost/api/v1.5/schema/master.xsd">\n    <Link rel="up" href="https://localhost/api/catalog/e8d953db-8dc9-46d5-9cab-329774cd2ad9" type="application/vnd.vmware.vcloud.catalog+xml"/>\n    <Link rel="down" href="https://localhost/api/catalogItem/d79fb542-6ad4-4c09-8cfc-f6104cbf67ad/metadata" type="application/vnd.vmware.vcloud.metadata+xml"/>\n    <Link rel="edit" href="https://localhost/api/catalogItem/d79fb542-6ad4-4c09-8cfc-f6104cbf67ad" type="application/vnd.vmware.vcloud.catalogItem+xml"/>\n    <Link rel="remove" href="https://localhost/api/catalogItem/d79fb542-6ad4-4c09-8cfc-f6104cbf67ad"/>\n    <Description/>\n    <Entity href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435" name="Ubuntu_no_nic" type="application/vnd.vmware.vcloud.vAppTemplate+xml"/>\n    <DateCreated>2017-10-14T23:52:58.097-07:00</DateCreated>\n    <VersionNumber>1</VersionNumber>\n</CatalogItem>"""

+catalogItem_xml = """<?xml version="1.0" ?>\n<CatalogItem xmlns="http://www.vmware.com/vcloud/v1.5" size="0" name="Ubuntu_no_nic" id="urn:vcloud:catalogitem:d79fb542-6ad4-4c09-8cfc-f6104cbf67ad" href="https://localhost/api/catalogItem/d79fb542-6ad4-4c09-8cfc-f6104cbf67ad" type="application/vnd.vmware.vcloud.catalogItem+xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/vcloud/v1.5 http://localhost/api/v1.5/schema/master.xsd">\n    <Link rel="up" href="https://localhost/api/catalog/e8d953db-8dc9-46d5-9cab-329774cd2ad9" type="application/vnd.vmware.vcloud.catalog+xml"/>\n    <Link rel="down" href="https://localhost/api/catalogItem/d79fb542-6ad4-4c09-8cfc-f6104cbf67ad/metadata" type="application/vnd.vmware.vcloud.metadata+xml"/>\n    <Link rel="edit" href="https://localhost/api/catalogItem/d79fb542-6ad4-4c09-8cfc-f6104cbf67ad" type="application/vnd.vmware.vcloud.catalogItem+xml"/>\n    <Link rel="remove" href="https://localhost/api/catalogItem/d79fb542-6ad4-4c09-8cfc-f6104cbf67ad"/>\n    <Description/>\n    <Entity href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435" name="Ubuntu_no_nic" type="application/vnd.vmware.vcloud.vAppTemplate+xml"/>\n    <DateCreated>2017-10-14T23:52:58.097-07:00</DateCreated>\n    <VersionNumber>1</VersionNumber>\n</CatalogItem>"""

 

-vapp_template_xml = """<?xml version="1.0" encoding="UTF-8"?>\n<VAppTemplate xmlns="http://www.vmware.com/vcloud/v1.5" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1" xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData" xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData" xmlns:vmw="http://www.vmware.com/schema/ovf" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" goldMaster="false" ovfDescriptorUploaded="true" status="8" name="Ubuntu_no_nic" id="urn:vcloud:vapptemplate:593e3130-ac0b-44f1-8289-14329dcc5435" href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435" type="application/vnd.vmware.vcloud.vAppTemplate+xml" xsi:schemaLocation="http://schemas.dmtf.org/ovf/envelope/1 http://schemas.dmtf.org/ovf/envelope/1/dsp8023_1.1.0.xsd http://www.vmware.com/vcloud/v1.5 http://localhost/api/v1.5/schema/master.xsd http://www.vmware.com/schema/ovf http://www.vmware.com/schema/ovf http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2.22.0/CIM_ResourceAllocationSettingData.xsd http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2.22.0/CIM_VirtualSystemSettingData.xsd">\n    <Link rel="up" href="https://localhost/api/vdc/2584137f-6541-4c04-a2a2-e56bfca14c69" type="application/vnd.vmware.vcloud.vdc+xml"/>\n    <Link rel="catalogItem" href="https://localhost/api/catalogItem/d79fb542-6ad4-4c09-8cfc-f6104cbf67ad" type="application/vnd.vmware.vcloud.catalogItem+xml"/>\n    <Link rel="remove" href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435"/>\n    <Link rel="edit" href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435" type="application/vnd.vmware.vcloud.vAppTemplate+xml"/>\n    <Link rel="enable" href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435/action/enableDownload"/>\n    <Link rel="disable" href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435/action/disableDownload"/>\n    <Link rel="ovf" href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435/ovf" type="text/xml"/>\n    <Link rel="storageProfile" href="https://localhost/api/vdcStorageProfile/950701fb-2b8a-4808-80f1-27d1170a2bfc" name="*" type="application/vnd.vmware.vcloud.vdcStorageProfile+xml"/>\n    <Link rel="down" href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435/owner" type="application/vnd.vmware.vcloud.owner+xml"/>\n    <Link rel="down" href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435/metadata" type="application/vnd.vmware.vcloud.metadata+xml"/>\n    <Link rel="down" href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435/productSections/" type="application/vnd.vmware.vcloud.productSections+xml"/>\n    <Description/>\n    <Owner type="application/vnd.vmware.vcloud.owner+xml">\n        <User href="https://localhost/api/admin/user/4e1905dc-7c0b-4013-b763-d01960853f49" name="system" type="application/vnd.vmware.admin.user+xml"/>\n    </Owner>\n    <Children>\n        <Vm goldMaster="false" status="8" name="Ubuntu_no_nic" id="urn:vcloud:vm:bd3fe155-3fb2-40a8-af48-89c276983166" href="https://localhost/api/vAppTemplate/vm-bd3fe155-3fb2-40a8-af48-89c276983166" type="application/vnd.vmware.vcloud.vm+xml">\n            <Link rel="up" href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435" type="application/vnd.vmware.vcloud.vAppTemplate+xml"/>\n            <Link rel="storageProfile" href="https://localhost/api/vdcStorageProfile/950701fb-2b8a-4808-80f1-27d1170a2bfc" type="application/vnd.vmware.vcloud.vdcStorageProfile+xml"/>\n            <Link rel="down" href="https://localhost/api/vAppTemplate/vm-bd3fe155-3fb2-40a8-af48-89c276983166/metadata" type="application/vnd.vmware.vcloud.metadata+xml"/>\n            <Link rel="down" href="https://localhost/api/vAppTemplate/vm-bd3fe155-3fb2-40a8-af48-89c276983166/productSections/" type="application/vnd.vmware.vcloud.productSections+xml"/>\n            <Description/>\n            <NetworkConnectionSection href="https://localhost/api/vAppTemplate/vm-bd3fe155-3fb2-40a8-af48-89c276983166/networkConnectionSection/" type="application/vnd.vmware.vcloud.networkConnectionSection+xml" ovf:required="false">\n                <ovf:Info>Specifies the available VM network connections</ovf:Info>\n            </NetworkConnectionSection>\n            <GuestCustomizationSection href="https://localhost/api/vAppTemplate/vm-bd3fe155-3fb2-40a8-af48-89c276983166/guestCustomizationSection/" type="application/vnd.vmware.vcloud.guestCustomizationSection+xml" ovf:required="false">\n                <ovf:Info>Specifies Guest OS Customization Settings</ovf:Info>\n                <Enabled>true</Enabled>\n                <ChangeSid>false</ChangeSid>\n                <VirtualMachineId>bd3fe155-3fb2-40a8-af48-89c276983166</VirtualMachineId>\n                <JoinDomainEnabled>false</JoinDomainEnabled>\n                <UseOrgSettings>false</UseOrgSettings>\n                <AdminPasswordEnabled>false</AdminPasswordEnabled>\n                <AdminPasswordAuto>true</AdminPasswordAuto>\n                <AdminAutoLogonEnabled>false</AdminAutoLogonEnabled>\n                <AdminAutoLogonCount>0</AdminAutoLogonCount>\n                <ResetPasswordRequired>false</ResetPasswordRequired>\n                <ComputerName>Ubuntunonic-001</ComputerName>\n            </GuestCustomizationSection>\n            <ovf:VirtualHardwareSection xmlns:vcloud="http://www.vmware.com/vcloud/v1.5" ovf:transport="" vcloud:type="application/vnd.vmware.vcloud.virtualHardwareSection+xml" vcloud:href="https://localhost/api/vAppTemplate/vm-bd3fe155-3fb2-40a8-af48-89c276983166/virtualHardwareSection/">\n                <ovf:Info>Virtual hardware requirements</ovf:Info>\n                <ovf:System>\n                    <vssd:ElementName>Virtual Hardware Family</vssd:ElementName>\n                    <vssd:InstanceID>0</vssd:InstanceID>\n                    <vssd:VirtualSystemIdentifier>Ubuntu_no_nic</vssd:VirtualSystemIdentifier>\n                    <vssd:VirtualSystemType>vmx-11</vssd:VirtualSystemType>\n                </ovf:System>\n                <ovf:Item>\n                    <rasd:Address>0</rasd:Address>\n                    <rasd:Description>SCSI Controller</rasd:Description>\n                    <rasd:ElementName>SCSI Controller 0</rasd:ElementName>\n                    <rasd:InstanceID>1</rasd:InstanceID>\n                    <rasd:ResourceSubType>lsilogic</rasd:ResourceSubType>\n                    <rasd:ResourceType>6</rasd:ResourceType>\n                </ovf:Item>\n                <ovf:Item>\n                    <rasd:AddressOnParent>0</rasd:AddressOnParent>\n                    <rasd:Description>Hard disk</rasd:Description>\n                    <rasd:ElementName>Hard disk 1</rasd:ElementName>\n                    <rasd:HostResource vcloud:storageProfileHref="https://localhost/api/vdcStorageProfile/950701fb-2b8a-4808-80f1-27d1170a2bfc" vcloud:busType="6" vcloud:busSubType="lsilogic" vcloud:capacity="5120" vcloud:storageProfileOverrideVmDefault="false"/>\n                    <rasd:InstanceID>2000</rasd:InstanceID>\n                    <rasd:Parent>1</rasd:Parent>\n                    <rasd:ResourceType>17</rasd:ResourceType>\n                    <rasd:VirtualQuantity>5368709120</rasd:VirtualQuantity>\n                    <rasd:VirtualQuantityUnits>byte</rasd:VirtualQuantityUnits>\n                </ovf:Item>\n                <ovf:Item>\n                    <rasd:Address>1</rasd:Address>\n                    <rasd:Description>IDE Controller</rasd:Description>\n                    <rasd:ElementName>IDE Controller 1</rasd:ElementName>\n                    <rasd:InstanceID>2</rasd:InstanceID>\n                    <rasd:ResourceType>5</rasd:ResourceType>\n                </ovf:Item>\n                <ovf:Item>\n                    <rasd:AddressOnParent>0</rasd:AddressOnParent>\n                    <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>\n                    <rasd:Description>CD/DVD Drive</rasd:Description>\n                    <rasd:ElementName>CD/DVD Drive 1</rasd:ElementName>\n                    <rasd:HostResource/>\n                    <rasd:InstanceID>3002</rasd:InstanceID>\n                    <rasd:Parent>2</rasd:Parent>\n                    <rasd:ResourceType>15</rasd:ResourceType>\n                </ovf:Item>\n                <ovf:Item>\n                    <rasd:AddressOnParent>0</rasd:AddressOnParent>\n                    <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>\n                    <rasd:Description>Floppy Drive</rasd:Description>\n                    <rasd:ElementName>Floppy Drive 1</rasd:ElementName>\n                    <rasd:HostResource/>\n                    <rasd:InstanceID>8000</rasd:InstanceID>\n                    <rasd:ResourceType>14</rasd:ResourceType>\n                </ovf:Item>\n                <ovf:Item>\n                    <rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>\n                    <rasd:Description>Number of Virtual CPUs</rasd:Description>\n                    <rasd:ElementName>1 virtual CPU(s)</rasd:ElementName>\n                    <rasd:InstanceID>3</rasd:InstanceID>\n                    <rasd:Reservation>0</rasd:Reservation>\n                    <rasd:ResourceType>3</rasd:ResourceType>\n                    <rasd:VirtualQuantity>1</rasd:VirtualQuantity>\n                    <rasd:Weight>0</rasd:Weight>\n                    <vmw:CoresPerSocket ovf:required="false">1</vmw:CoresPerSocket>\n                </ovf:Item>\n                <ovf:Item>\n                    <rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>\n                    <rasd:Description>Memory Size</rasd:Description>\n                    <rasd:ElementName>1024 MB of memory</rasd:ElementName>\n                    <rasd:InstanceID>4</rasd:InstanceID>\n                    <rasd:Reservation>0</rasd:Reservation>\n                    <rasd:ResourceType>4</rasd:ResourceType>\n                    <rasd:VirtualQuantity>1024</rasd:VirtualQuantity>\n                    <rasd:Weight>0</rasd:Weight>\n                </ovf:Item>\n                <Link rel="down" href="https://localhost/api/vAppTemplate/vm-bd3fe155-3fb2-40a8-af48-89c276983166/virtualHardwareSection/cpu" type="application/vnd.vmware.vcloud.rasdItem+xml"/>\n                <Link rel="down" href="https://localhost/api/vAppTemplate/vm-bd3fe155-3fb2-40a8-af48-89c276983166/virtualHardwareSection/memory" type="application/vnd.vmware.vcloud.rasdItem+xml"/>\n                <Link rel="down" href="https://localhost/api/vAppTemplate/vm-bd3fe155-3fb2-40a8-af48-89c276983166/virtualHardwareSection/disks" type="application/vnd.vmware.vcloud.rasdItemsList+xml"/>\n                <Link rel="down" href="https://localhost/api/vAppTemplate/vm-bd3fe155-3fb2-40a8-af48-89c276983166/virtualHardwareSection/media" type="application/vnd.vmware.vcloud.rasdItemsList+xml"/>\n                <Link rel="down" href="https://localhost/api/vAppTemplate/vm-bd3fe155-3fb2-40a8-af48-89c276983166/virtualHardwareSection/networkCards" type="application/vnd.vmware.vcloud.rasdItemsList+xml"/>\n                <Link rel="down" href="https://localhost/api/vAppTemplate/vm-bd3fe155-3fb2-40a8-af48-89c276983166/virtualHardwareSection/serialPorts" type="application/vnd.vmware.vcloud.rasdItemsList+xml"/>\n            </ovf:VirtualHardwareSection>\n            <VAppScopedLocalId>Ubuntu_no_nic</VAppScopedLocalId>\n            <DateCreated>2017-10-14T23:52:58.790-07:00</DateCreated>\n        </Vm>\n    </Children>\n    <ovf:NetworkSection xmlns:vcloud="http://www.vmware.com/vcloud/v1.5" vcloud:type="application/vnd.vmware.vcloud.networkSection+xml" vcloud:href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435/networkSection/">\n        <ovf:Info>The list of logical networks</ovf:Info>\n    </ovf:NetworkSection>\n    <NetworkConfigSection href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435/networkConfigSection/" type="application/vnd.vmware.vcloud.networkConfigSection+xml" ovf:required="false">\n        <ovf:Info>The configuration parameters for logical networks</ovf:Info>\n    </NetworkConfigSection>\n    <LeaseSettingsSection href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435/leaseSettingsSection/" type="application/vnd.vmware.vcloud.leaseSettingsSection+xml" ovf:required="false">\n        <ovf:Info>Lease settings section</ovf:Info>\n        <Link rel="edit" href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435/leaseSettingsSection/" type="application/vnd.vmware.vcloud.leaseSettingsSection+xml"/>\n        <StorageLeaseInSeconds>7776000</StorageLeaseInSeconds>\n        <StorageLeaseExpiration>2018-08-22T02:41:54.567-07:00</StorageLeaseExpiration>\n    </LeaseSettingsSection>\n    <CustomizationSection goldMaster="false" href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435/customizationSection/" type="application/vnd.vmware.vcloud.customizationSection+xml" ovf:required="false">\n        <ovf:Info>VApp template customization section</ovf:Info>\n        <CustomizeOnInstantiate>true</CustomizeOnInstantiate>\n    </CustomizationSection>\n    <DateCreated>2017-10-14T23:52:58.790-07:00</DateCreated>\n</VAppTemplate>\n"""

+vapp_template_xml = """<?xml version="1.0" ?>\n<VAppTemplate xmlns="http://www.vmware.com/vcloud/v1.5" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1" xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData" xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData" xmlns:vmw="http://www.vmware.com/schema/ovf" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" goldMaster="false" ovfDescriptorUploaded="true" status="8" name="Ubuntu_no_nic" id="urn:vcloud:vapptemplate:593e3130-ac0b-44f1-8289-14329dcc5435" href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435" type="application/vnd.vmware.vcloud.vAppTemplate+xml" xsi:schemaLocation="http://schemas.dmtf.org/ovf/envelope/1 http://schemas.dmtf.org/ovf/envelope/1/dsp8023_1.1.0.xsd http://www.vmware.com/vcloud/v1.5 http://localhost/api/v1.5/schema/master.xsd http://www.vmware.com/schema/ovf http://www.vmware.com/schema/ovf http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2.22.0/CIM_ResourceAllocationSettingData.xsd http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2.22.0/CIM_VirtualSystemSettingData.xsd">\n    <Link rel="up" href="https://localhost/api/vdc/2584137f-6541-4c04-a2a2-e56bfca14c69" type="application/vnd.vmware.vcloud.vdc+xml"/>\n    <Link rel="catalogItem" href="https://localhost/api/catalogItem/d79fb542-6ad4-4c09-8cfc-f6104cbf67ad" type="application/vnd.vmware.vcloud.catalogItem+xml"/>\n    <Link rel="remove" href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435"/>\n    <Link rel="edit" href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435" type="application/vnd.vmware.vcloud.vAppTemplate+xml"/>\n    <Link rel="enable" href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435/action/enableDownload"/>\n    <Link rel="disable" href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435/action/disableDownload"/>\n    <Link rel="ovf" href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435/ovf" type="text/xml"/>\n    <Link rel="storageProfile" href="https://localhost/api/vdcStorageProfile/950701fb-2b8a-4808-80f1-27d1170a2bfc" name="*" type="application/vnd.vmware.vcloud.vdcStorageProfile+xml"/>\n    <Link rel="down" href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435/owner" type="application/vnd.vmware.vcloud.owner+xml"/>\n    <Link rel="down" href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435/metadata" type="application/vnd.vmware.vcloud.metadata+xml"/>\n    <Link rel="down" href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435/productSections/" type="application/vnd.vmware.vcloud.productSections+xml"/>\n    <Description/>\n    <Owner type="application/vnd.vmware.vcloud.owner+xml">\n        <User href="https://localhost/api/admin/user/4e1905dc-7c0b-4013-b763-d01960853f49" name="system" type="application/vnd.vmware.admin.user+xml"/>\n    </Owner>\n    <Children>\n        <Vm goldMaster="false" status="8" name="Ubuntu_no_nic" id="urn:vcloud:vm:bd3fe155-3fb2-40a8-af48-89c276983166" href="https://localhost/api/vAppTemplate/vm-bd3fe155-3fb2-40a8-af48-89c276983166" type="application/vnd.vmware.vcloud.vm+xml">\n            <Link rel="up" href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435" type="application/vnd.vmware.vcloud.vAppTemplate+xml"/>\n            <Link rel="storageProfile" href="https://localhost/api/vdcStorageProfile/950701fb-2b8a-4808-80f1-27d1170a2bfc" type="application/vnd.vmware.vcloud.vdcStorageProfile+xml"/>\n            <Link rel="down" href="https://localhost/api/vAppTemplate/vm-bd3fe155-3fb2-40a8-af48-89c276983166/metadata" type="application/vnd.vmware.vcloud.metadata+xml"/>\n            <Link rel="down" href="https://localhost/api/vAppTemplate/vm-bd3fe155-3fb2-40a8-af48-89c276983166/productSections/" type="application/vnd.vmware.vcloud.productSections+xml"/>\n            <Description/>\n            <NetworkConnectionSection href="https://localhost/api/vAppTemplate/vm-bd3fe155-3fb2-40a8-af48-89c276983166/networkConnectionSection/" type="application/vnd.vmware.vcloud.networkConnectionSection+xml" ovf:required="false">\n                <ovf:Info>Specifies the available VM network connections</ovf:Info>\n            </NetworkConnectionSection>\n            <GuestCustomizationSection href="https://localhost/api/vAppTemplate/vm-bd3fe155-3fb2-40a8-af48-89c276983166/guestCustomizationSection/" type="application/vnd.vmware.vcloud.guestCustomizationSection+xml" ovf:required="false">\n                <ovf:Info>Specifies Guest OS Customization Settings</ovf:Info>\n                <Enabled>true</Enabled>\n                <ChangeSid>false</ChangeSid>\n                <VirtualMachineId>bd3fe155-3fb2-40a8-af48-89c276983166</VirtualMachineId>\n                <JoinDomainEnabled>false</JoinDomainEnabled>\n                <UseOrgSettings>false</UseOrgSettings>\n                <AdminPasswordEnabled>false</AdminPasswordEnabled>\n                <AdminPasswordAuto>true</AdminPasswordAuto>\n                <AdminAutoLogonEnabled>false</AdminAutoLogonEnabled>\n                <AdminAutoLogonCount>0</AdminAutoLogonCount>\n                <ResetPasswordRequired>false</ResetPasswordRequired>\n                <ComputerName>Ubuntunonic-001</ComputerName>\n            </GuestCustomizationSection>\n            <ovf:VirtualHardwareSection xmlns:vcloud="http://www.vmware.com/vcloud/v1.5" ovf:transport="" vcloud:type="application/vnd.vmware.vcloud.virtualHardwareSection+xml" vcloud:href="https://localhost/api/vAppTemplate/vm-bd3fe155-3fb2-40a8-af48-89c276983166/virtualHardwareSection/">\n                <ovf:Info>Virtual hardware requirements</ovf:Info>\n                <ovf:System>\n                    <vssd:ElementName>Virtual Hardware Family</vssd:ElementName>\n                    <vssd:InstanceID>0</vssd:InstanceID>\n                    <vssd:VirtualSystemIdentifier>Ubuntu_no_nic</vssd:VirtualSystemIdentifier>\n                    <vssd:VirtualSystemType>vmx-11</vssd:VirtualSystemType>\n                </ovf:System>\n                <ovf:Item>\n                    <rasd:Address>0</rasd:Address>\n                    <rasd:Description>SCSI Controller</rasd:Description>\n                    <rasd:ElementName>SCSI Controller 0</rasd:ElementName>\n                    <rasd:InstanceID>1</rasd:InstanceID>\n                    <rasd:ResourceSubType>lsilogic</rasd:ResourceSubType>\n                    <rasd:ResourceType>6</rasd:ResourceType>\n                </ovf:Item>\n                <ovf:Item>\n                    <rasd:AddressOnParent>0</rasd:AddressOnParent>\n                    <rasd:Description>Hard disk</rasd:Description>\n                    <rasd:ElementName>Hard disk 1</rasd:ElementName>\n                    <rasd:HostResource vcloud:storageProfileHref="https://localhost/api/vdcStorageProfile/950701fb-2b8a-4808-80f1-27d1170a2bfc" vcloud:busType="6" vcloud:busSubType="lsilogic" vcloud:capacity="5120" vcloud:storageProfileOverrideVmDefault="false"/>\n                    <rasd:InstanceID>2000</rasd:InstanceID>\n                    <rasd:Parent>1</rasd:Parent>\n                    <rasd:ResourceType>17</rasd:ResourceType>\n                    <rasd:VirtualQuantity>5368709120</rasd:VirtualQuantity>\n                    <rasd:VirtualQuantityUnits>byte</rasd:VirtualQuantityUnits>\n                </ovf:Item>\n                <ovf:Item>\n                    <rasd:Address>1</rasd:Address>\n                    <rasd:Description>IDE Controller</rasd:Description>\n                    <rasd:ElementName>IDE Controller 1</rasd:ElementName>\n                    <rasd:InstanceID>2</rasd:InstanceID>\n                    <rasd:ResourceType>5</rasd:ResourceType>\n                </ovf:Item>\n                <ovf:Item>\n                    <rasd:AddressOnParent>0</rasd:AddressOnParent>\n                    <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>\n                    <rasd:Description>CD/DVD Drive</rasd:Description>\n                    <rasd:ElementName>CD/DVD Drive 1</rasd:ElementName>\n                    <rasd:HostResource/>\n                    <rasd:InstanceID>3002</rasd:InstanceID>\n                    <rasd:Parent>2</rasd:Parent>\n                    <rasd:ResourceType>15</rasd:ResourceType>\n                </ovf:Item>\n                <ovf:Item>\n                    <rasd:AddressOnParent>0</rasd:AddressOnParent>\n                    <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>\n                    <rasd:Description>Floppy Drive</rasd:Description>\n                    <rasd:ElementName>Floppy Drive 1</rasd:ElementName>\n                    <rasd:HostResource/>\n                    <rasd:InstanceID>8000</rasd:InstanceID>\n                    <rasd:ResourceType>14</rasd:ResourceType>\n                </ovf:Item>\n                <ovf:Item>\n                    <rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>\n                    <rasd:Description>Number of Virtual CPUs</rasd:Description>\n                    <rasd:ElementName>1 virtual CPU(s)</rasd:ElementName>\n                    <rasd:InstanceID>3</rasd:InstanceID>\n                    <rasd:Reservation>0</rasd:Reservation>\n                    <rasd:ResourceType>3</rasd:ResourceType>\n                    <rasd:VirtualQuantity>1</rasd:VirtualQuantity>\n                    <rasd:Weight>0</rasd:Weight>\n                    <vmw:CoresPerSocket ovf:required="false">1</vmw:CoresPerSocket>\n                </ovf:Item>\n                <ovf:Item>\n                    <rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>\n                    <rasd:Description>Memory Size</rasd:Description>\n                    <rasd:ElementName>1024 MB of memory</rasd:ElementName>\n                    <rasd:InstanceID>4</rasd:InstanceID>\n                    <rasd:Reservation>0</rasd:Reservation>\n                    <rasd:ResourceType>4</rasd:ResourceType>\n                    <rasd:VirtualQuantity>1024</rasd:VirtualQuantity>\n                    <rasd:Weight>0</rasd:Weight>\n                </ovf:Item>\n                <Link rel="down" href="https://localhost/api/vAppTemplate/vm-bd3fe155-3fb2-40a8-af48-89c276983166/virtualHardwareSection/cpu" type="application/vnd.vmware.vcloud.rasdItem+xml"/>\n                <Link rel="down" href="https://localhost/api/vAppTemplate/vm-bd3fe155-3fb2-40a8-af48-89c276983166/virtualHardwareSection/memory" type="application/vnd.vmware.vcloud.rasdItem+xml"/>\n                <Link rel="down" href="https://localhost/api/vAppTemplate/vm-bd3fe155-3fb2-40a8-af48-89c276983166/virtualHardwareSection/disks" type="application/vnd.vmware.vcloud.rasdItemsList+xml"/>\n                <Link rel="down" href="https://localhost/api/vAppTemplate/vm-bd3fe155-3fb2-40a8-af48-89c276983166/virtualHardwareSection/media" type="application/vnd.vmware.vcloud.rasdItemsList+xml"/>\n                <Link rel="down" href="https://localhost/api/vAppTemplate/vm-bd3fe155-3fb2-40a8-af48-89c276983166/virtualHardwareSection/networkCards" type="application/vnd.vmware.vcloud.rasdItemsList+xml"/>\n                <Link rel="down" href="https://localhost/api/vAppTemplate/vm-bd3fe155-3fb2-40a8-af48-89c276983166/virtualHardwareSection/serialPorts" type="application/vnd.vmware.vcloud.rasdItemsList+xml"/>\n            </ovf:VirtualHardwareSection>\n            <VAppScopedLocalId>Ubuntu_no_nic</VAppScopedLocalId>\n            <DateCreated>2017-10-14T23:52:58.790-07:00</DateCreated>\n        </Vm>\n    </Children>\n    <ovf:NetworkSection xmlns:vcloud="http://www.vmware.com/vcloud/v1.5" vcloud:type="application/vnd.vmware.vcloud.networkSection+xml" vcloud:href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435/networkSection/">\n        <ovf:Info>The list of logical networks</ovf:Info>\n    </ovf:NetworkSection>\n    <NetworkConfigSection href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435/networkConfigSection/" type="application/vnd.vmware.vcloud.networkConfigSection+xml" ovf:required="false">\n        <ovf:Info>The configuration parameters for logical networks</ovf:Info>\n    </NetworkConfigSection>\n    <LeaseSettingsSection href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435/leaseSettingsSection/" type="application/vnd.vmware.vcloud.leaseSettingsSection+xml" ovf:required="false">\n        <ovf:Info>Lease settings section</ovf:Info>\n        <Link rel="edit" href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435/leaseSettingsSection/" type="application/vnd.vmware.vcloud.leaseSettingsSection+xml"/>\n        <StorageLeaseInSeconds>7776000</StorageLeaseInSeconds>\n        <StorageLeaseExpiration>2018-08-22T02:41:54.567-07:00</StorageLeaseExpiration>\n    </LeaseSettingsSection>\n    <CustomizationSection goldMaster="false" href="https://localhost/api/vAppTemplate/vappTemplate-593e3130-ac0b-44f1-8289-14329dcc5435/customizationSection/" type="application/vnd.vmware.vcloud.customizationSection+xml" ovf:required="false">\n        <ovf:Info>VApp template customization section</ovf:Info>\n        <CustomizeOnInstantiate>true</CustomizeOnInstantiate>\n    </CustomizationSection>\n    <DateCreated>2017-10-14T23:52:58.790-07:00</DateCreated>\n</VAppTemplate>\n"""

 

-deployed_vapp_xml = """<?xml version="1.0" encoding="UTF-8"?>\n<VApp xmlns="http://www.vmware.com/vcloud/v1.5" ovfDescriptorUploaded="true" deployed="false" status="0" name="Test1_vm-978d608b-07e4-4733-9c15-b66bc8ee310a" id="urn:vcloud:vapp:8b3ab861-cc53-4bd8-bdd0-85a74af76c61" href="https://localhost/api/vApp/vapp-8b3ab861-cc53-4bd8-bdd0-85a74af76c61" type="application/vnd.vmware.vcloud.vApp+xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/vcloud/v1.5 http://localhost/api/v1.5/schema/master.xsd">\n    <Link rel="down" href="https://localhost/api/vApp/vapp-8b3ab861-cc53-4bd8-bdd0-85a74af76c61/controlAccess/" type="application/vnd.vmware.vcloud.controlAccess+xml"/>\n    <Link rel="up" href="https://localhost/api/vdc/2584137f-6541-4c04-a2a2-e56bfca14c69" type="application/vnd.vmware.vcloud.vdc+xml"/>\n    <Link rel="down" href="https://localhost/api/vApp/vapp-8b3ab861-cc53-4bd8-bdd0-85a74af76c61/owner" type="application/vnd.vmware.vcloud.owner+xml"/>\n    <Link rel="down" href="https://localhost/api/vApp/vapp-8b3ab861-cc53-4bd8-bdd0-85a74af76c61/metadata" type="application/vnd.vmware.vcloud.metadata+xml"/>\n    <Link rel="ovf" href="https://localhost/api/vApp/vapp-8b3ab861-cc53-4bd8-bdd0-85a74af76c61/ovf" type="text/xml"/>\n    <Link rel="down" href="https://localhost/api/vApp/vapp-8b3ab861-cc53-4bd8-bdd0-85a74af76c61/productSections/" type="application/vnd.vmware.vcloud.productSections+xml"/>\n    <Description>Vapp instantiation</Description>\n    <Tasks>\n        <Task cancelRequested="false" expiryTime="2018-08-31T01:14:34.292-07:00" operation="Creating Virtual Application Test1_vm-978d608b-07e4-4733-9c15-b66bc8ee310a(8b3ab861-cc53-4bd8-bdd0-85a74af76c61)" operationName="vdcInstantiateVapp" serviceNamespace="com.vmware.vcloud" startTime="2018-06-02T01:14:34.292-07:00" status="queued" name="task" id="urn:vcloud:task:1d588451-6b7d-43f4-b8c7-c9155dcd715a" href="https://localhost/api/task/1d588451-6b7d-43f4-b8c7-c9155dcd715a" type="application/vnd.vmware.vcloud.task+xml">\n            <Owner href="https://localhost/api/vApp/vapp-8b3ab861-cc53-4bd8-bdd0-85a74af76c61" name="Test1_vm-978d608b-07e4-4733-9c15-b66bc8ee310a" type="application/vnd.vmware.vcloud.vApp+xml"/>\n            <User href="https://localhost/api/admin/user/f7b6beba-96db-4674-b187-675ed1873c8c" name="orgadmin" type="application/vnd.vmware.admin.user+xml"/>\n            <Organization href="https://localhost/api/org/2cb3dffb-5c51-4355-8406-28553ead28ac" name="Org3" type="application/vnd.vmware.vcloud.org+xml"/>\n            <Progress>1</Progress>\n            <Details/>\n        </Task>\n    </Tasks>\n    <DateCreated>2018-06-02T01:14:32.870-07:00</DateCreated>\n    <Owner type="application/vnd.vmware.vcloud.owner+xml">\n        <User href="https://localhost/api/admin/user/f7b6beba-96db-4674-b187-675ed1873c8c" name="orgadmin" type="application/vnd.vmware.admin.user+xml"/>\n    </Owner>\n    <InMaintenanceMode>false</InMaintenanceMode>\n</VApp>"""

+deployed_vapp_xml = """<?xml version="1.0" ?>\n<VApp xmlns="http://www.vmware.com/vcloud/v1.5" ovfDescriptorUploaded="true" deployed="false" status="0" name="Test1_vm-978d608b-07e4-4733-9c15-b66bc8ee310a" id="urn:vcloud:vapp:8b3ab861-cc53-4bd8-bdd0-85a74af76c61" href="https://localhost/api/vApp/vapp-8b3ab861-cc53-4bd8-bdd0-85a74af76c61" type="application/vnd.vmware.vcloud.vApp+xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/vcloud/v1.5 http://localhost/api/v1.5/schema/master.xsd">\n    <Link rel="down" href="https://localhost/api/vApp/vapp-8b3ab861-cc53-4bd8-bdd0-85a74af76c61/controlAccess/" type="application/vnd.vmware.vcloud.controlAccess+xml"/>\n    <Link rel="up" href="https://localhost/api/vdc/2584137f-6541-4c04-a2a2-e56bfca14c69" type="application/vnd.vmware.vcloud.vdc+xml"/>\n    <Link rel="down" href="https://localhost/api/vApp/vapp-8b3ab861-cc53-4bd8-bdd0-85a74af76c61/owner" type="application/vnd.vmware.vcloud.owner+xml"/>\n    <Link rel="down" href="https://localhost/api/vApp/vapp-8b3ab861-cc53-4bd8-bdd0-85a74af76c61/metadata" type="application/vnd.vmware.vcloud.metadata+xml"/>\n    <Link rel="ovf" href="https://localhost/api/vApp/vapp-8b3ab861-cc53-4bd8-bdd0-85a74af76c61/ovf" type="text/xml"/>\n    <Link rel="down" href="https://localhost/api/vApp/vapp-8b3ab861-cc53-4bd8-bdd0-85a74af76c61/productSections/" type="application/vnd.vmware.vcloud.productSections+xml"/>\n    <Description>Vapp instantiation</Description>\n    <Tasks>\n        <Task cancelRequested="false" expiryTime="2018-08-31T01:14:34.292-07:00" operation="Creating Virtual Application Test1_vm-978d608b-07e4-4733-9c15-b66bc8ee310a(8b3ab861-cc53-4bd8-bdd0-85a74af76c61)" operationName="vdcInstantiateVapp" serviceNamespace="com.vmware.vcloud" startTime="2018-06-02T01:14:34.292-07:00" status="queued" name="task" id="urn:vcloud:task:1d588451-6b7d-43f4-b8c7-c9155dcd715a" href="https://localhost/api/task/1d588451-6b7d-43f4-b8c7-c9155dcd715a" type="application/vnd.vmware.vcloud.task+xml">\n            <Owner href="https://localhost/api/vApp/vapp-8b3ab861-cc53-4bd8-bdd0-85a74af76c61" name="Test1_vm-978d608b-07e4-4733-9c15-b66bc8ee310a" type="application/vnd.vmware.vcloud.vApp+xml"/>\n            <User href="https://localhost/api/admin/user/f7b6beba-96db-4674-b187-675ed1873c8c" name="orgadmin" type="application/vnd.vmware.admin.user+xml"/>\n            <Organization href="https://localhost/api/org/2cb3dffb-5c51-4355-8406-28553ead28ac" name="Org3" type="application/vnd.vmware.vcloud.org+xml"/>\n            <Progress>1</Progress>\n            <Details/>\n        </Task>\n    </Tasks>\n    <DateCreated>2018-06-02T01:14:32.870-07:00</DateCreated>\n    <Owner type="application/vnd.vmware.vcloud.owner+xml">\n        <User href="https://localhost/api/admin/user/f7b6beba-96db-4674-b187-675ed1873c8c" name="orgadmin" type="application/vnd.vmware.admin.user+xml"/>\n    </Owner>\n    <InMaintenanceMode>false</InMaintenanceMode>\n</VApp>"""

diff --git a/osm_ro/vimconn_vmware.py b/RO-VIM-vmware/osm_rovim_vmware/vimconn_vmware.py
similarity index 98%
rename from osm_ro/vimconn_vmware.py
rename to RO-VIM-vmware/osm_rovim_vmware/vimconn_vmware.py
index 7f915b5..171f7d4 100644
--- a/osm_ro/vimconn_vmware.py
+++ b/RO-VIM-vmware/osm_rovim_vmware/vimconn_vmware.py
@@ -27,7 +27,7 @@
 """
 from progressbar import Percentage, Bar, ETA, FileTransferSpeed, ProgressBar
 
-import vimconn
+from osm_ro import vimconn
 import os
 import shutil
 import subprocess
@@ -55,9 +55,9 @@
 import json
 import time
 import uuid
-import httplib
+# import httplib
 #For python3
-#import http.client
+#import http.client  # TODO py3 check
 import hashlib
 import socket
 import struct
@@ -266,7 +266,7 @@
         elif index == "config":
             return self.config
         else:
-            raise KeyError("Invalid key '%s'" % str(index))
+            raise KeyError("Invalid key '{}'".format(index))
 
     def __setitem__(self, index, value):
         if index == 'name':
@@ -290,7 +290,7 @@
         elif index == 'url_admin':
             self.url_admin = value
         else:
-            raise KeyError("Invalid key '%s'" % str(index))
+            raise KeyError("Invalid key '{}'".format(index))
 
     def connect_as_admin(self):
         """ Method connect as pvdc admin user to vCloud director.
@@ -446,9 +446,7 @@
                     raise vimconn.vimconnNotFoundException("Fail to get tenant {}".format(tenant_id))
 
                 lxmlroot_respond = lxmlElementTree.fromstring(response.content)
-                namespaces = {prefix:uri for prefix,uri in lxmlroot_respond.nsmap.iteritems() if prefix}
-                #For python3
-                #namespaces = {prefix:uri for prefix,uri in lxmlroot_respond.nsmap.items() if prefix}
+                namespaces = {prefix: uri for prefix, uri in lxmlroot_respond.nsmap.items() if prefix}
                 namespaces["xmlns"]= "http://www.vmware.com/vcloud/v1.5"
                 vdc_remove_href = lxmlroot_respond.find("xmlns:Link[@rel='remove']",namespaces).attrib['href']
                 vdc_remove_href = vdc_remove_href + '?recursive=true&force=true'
@@ -989,9 +987,7 @@
             raise vimconn.vimconnNotFoundException("Fail to get image {}".format(image_id))
 
         lxmlroot_respond = lxmlElementTree.fromstring(response.content)
-        namespaces = {prefix:uri for prefix,uri in lxmlroot_respond.nsmap.iteritems() if prefix}
-        #For python3
-        #namespaces = {prefix:uri for prefix,uri in lxmlroot_respond.nsmap.items() if prefix}
+        namespaces = {prefix: uri for prefix, uri in lxmlroot_respond.nsmap.items() if prefix}
         namespaces["xmlns"]= "http://www.vmware.com/vcloud/v1.5"
 
         catalogItems_section = lxmlroot_respond.find("xmlns:CatalogItems",namespaces)
@@ -1012,9 +1008,7 @@
                                                                                     image_id))
 
             lxmlroot_respond = lxmlElementTree.fromstring(response.content)
-            namespaces = {prefix:uri for prefix,uri in lxmlroot_respond.nsmap.iteritems() if prefix}
-            #For python3
-            #namespaces = {prefix:uri for prefix,uri in lxmlroot_respond.nsmap.items() if prefix}
+            namespaces = {prefix: uri for prefix, uri in lxmlroot_respond.nsmap.items() if prefix}
             namespaces["xmlns"]= "http://www.vmware.com/vcloud/v1.5"
             catalogitem_remove_href = lxmlroot_respond.find("xmlns:Link[@rel='remove']",namespaces).attrib['href']
 
@@ -1181,7 +1175,7 @@
                         while bytes_transferred < statinfo.st_size:
                             my_bytes = f.read(chunk_bytes)
                             if len(my_bytes) <= chunk_bytes:
-                                headers['Content-Range'] = 'bytes %s-%s/%s' % (
+                                headers['Content-Range'] = 'bytes {}-{}/{}'.format(
                                     bytes_transferred, len(my_bytes) - 1, statinfo.st_size)
                                 headers['Content-Length'] = str(len(my_bytes))
                                 response = requests.put(url=hrefvmdk,
@@ -1194,7 +1188,7 @@
                                         progress_bar.update(bytes_transferred)
                                 else:
                                     self.logger.debug(
-                                        'file upload failed with error: [%s] %s' % (response.status_code,
+                                        'file upload failed with error: [{}] {}'.format(response.status_code,
                                                                                         response.content))
 
                                     f.close()
@@ -1422,11 +1416,8 @@
             return None
         # UUID has following format https://host/api/vApp/vapp-30da58a3-e7c7-4d09-8f68-d4c8201169cf
         try:
-            refs = filter(lambda ref: ref.name == vapp_name and ref.type_ == 'application/vnd.vmware.vcloud.vApp+xml',
-                          vdc.ResourceEntities.ResourceEntity)
-            #For python3
-            #refs = [ref for ref in vdc.ResourceEntities.ResourceEntity\
-            #         if ref.name == vapp_name and ref.type_ == 'application/vnd.vmware.vcloud.vApp+xml']
+            refs = [ref for ref in vdc.ResourceEntities.ResourceEntity \
+                    if ref.name == vapp_name and ref.type_ == 'application/vnd.vmware.vcloud.vApp+xml']
             if len(refs) == 1:
                 return refs[0].href.split("vapp")[1][1:]
         except Exception as e:
@@ -1448,12 +1439,8 @@
                 :param vapp_uuid:
         """
         try:
-            refs = filter(lambda ref:
-                          ref.type_ == 'application/vnd.vmware.vcloud.vApp+xml',
-                          vdc.ResourceEntities.ResourceEntity)
-            #For python3
-            #refs = [ref for ref in vdc.ResourceEntities.ResourceEntity\
-            #         if ref.type_ == 'application/vnd.vmware.vcloud.vApp+xml']
+            refs = [ref for ref in vdc.ResourceEntities.ResourceEntity\
+                     if ref.type_ == 'application/vnd.vmware.vcloud.vApp+xml']
             for ref in refs:
                 vappid = ref.href.split("vapp")[1][1:]
                 # find vapp with respected vapp uuid
@@ -1939,9 +1926,7 @@
 
                 if primary_netname is not None:
                     self.logger.debug("new_vminstance(): Filtering by net name {}".format(interface_net_name))
-                    nets = filter(lambda n: n.get('name') == interface_net_name, self.get_network_list())
-                    #For python3
-                    #nets = [n for n in self.get_network_list() if n.get('name') == interface_net_name]
+                    nets = [n for n in self.get_network_list() if n.get('name') == interface_net_name]
                     if len(nets) == 1:
                         self.logger.info("new_vminstance(): Found requested network: {}".format(nets[0].get('name')))
 
@@ -3075,7 +3060,6 @@
         except XmlElementTree.ParseError as Err:
             self.logger.debug("ParseError in response from NSX Manager {}".format(Err.message), exc_info=True)
 
-
     def action_vminstance(self, vm__vim_uuid=None, action_dict=None, created_items={}):
         """Send and action over a VM instance from VIM
         Returns the vm_id if the action was successfully sent to the VIM"""
@@ -3086,7 +3070,7 @@
 
         org, vdc = self.get_vdc_details()
         if vdc is None:
-            raise  vimconn.vimconnException("Failed to get a reference of VDC for a tenant {}".format(self.tenant_name))
+            raise vimconn.vimconnException("Failed to get a reference of VDC for a tenant {}".format(self.tenant_name))
 
         vapp_name = self.get_namebyvappid(vm__vim_uuid)
         if vapp_name is None:
@@ -3120,9 +3104,7 @@
                 result = self.client.get_task_monitor().wait_for_success(task=poweron_task)
                 self.instance_actions_result("resume", result, vapp_name)
             elif "shutoff" in action_dict or "shutdown" in action_dict:
-                action_name , value = action_dict.items()[0]
-                #For python3
-                #action_name , value = list(action_dict.items())[0]
+                action_name , value = list(action_dict.items())[0]
                 self.logger.info("action_vminstance: {} vApp: {}".format(action_name, vapp_name))
                 shutdown_task = vapp.shutdown()
                 result = self.client.get_task_monitor().wait_for_success(task=shutdown_task)
@@ -3306,7 +3288,7 @@
             org_dict = self.get_org(self.org_uuid)
             if org_dict and 'networks' in org_dict:
                 org_network_dict = org_dict['networks']
-                for net_uuid,net_name in org_network_dict.iteritems():
+                for net_uuid, net_name in org_network_dict.items():
                     if net_name == network_name:
                         return net_uuid
 
@@ -3536,11 +3518,8 @@
         vm_list_rest_call = ''.join(url_list)
 
         if not (not vca.vcloud_session or not vca.vcloud_session.organization):
-            refs = filter(lambda ref: ref.name == vdc_name and ref.type_ == 'application/vnd.vmware.vcloud.vdc+xml',
-                          vca.vcloud_session.organization.Link)
-            #For python3
-            #refs = [ref for ref in vca.vcloud_session.organization.Link if ref.name == vdc_name and\
-            #        ref.type_ == 'application/vnd.vmware.vcloud.vdc+xml']
+            refs = [ref for ref in vca.vcloud_session.organization.Link if ref.name == vdc_name and
+                    ref.type_ == 'application/vnd.vmware.vcloud.vdc+xml']
             if len(refs) == 1:
                 response = Http.get(url=vm_list_rest_call,
                                     headers=vca.vcloud_session.get_vcloud_headers(),
@@ -4516,9 +4495,7 @@
             return None
         try:
             lxmlroot_respond = lxmlElementTree.fromstring(response.content)
-            namespaces = {prefix:uri for prefix,uri in lxmlroot_respond.nsmap.iteritems() if prefix}
-            #For python3
-            #namespaces = {prefix:uri for prefix,uri in lxmlroot_respond.nsmap.items() if prefix}
+            namespaces = {prefix: uri for prefix, uri in lxmlroot_respond.nsmap.items() if prefix}
             namespaces["xmlns"]= "http://www.vmware.com/vcloud/v1.5"
 
             for item in lxmlroot_respond.iterfind('xmlns:Item',namespaces):
@@ -4960,7 +4937,7 @@
 
             bytexml = bytes(bytearray(response.content, encoding='utf-8'))
             contentelem = lxmlElementTree.XML(bytexml)
-            namespaces = {prefix:uri for prefix,uri in contentelem.nsmap.iteritems() if prefix}
+            namespaces = {prefix:uri for prefix,uri in contentelem.nsmap.items() if prefix}
             namespaces["xmlns"]= "http://www.vmware.com/vcloud/v1.5"
 
             # Find the reservation element in the response
@@ -5036,7 +5013,7 @@
 
         bytexml = bytes(bytearray(data, encoding='utf-8'))
         newelem = lxmlElementTree.XML(bytexml)
-        namespaces = {prefix: uri for prefix, uri in newelem.nsmap.iteritems() if prefix}
+        namespaces = {prefix: uri for prefix, uri in newelem.nsmap.items() if prefix}
         namespaces["xmlns"] = "http://www.vmware.com/vcloud/v1.5"
         nwcfglist = newelem.findall(".//xmlns:NetworkConfig", namespaces)
 
@@ -5655,9 +5632,7 @@
         try:
             #Find but type & max of instance IDs assigned to disks
             lxmlroot_respond = lxmlElementTree.fromstring(response.content)
-            namespaces = {prefix:uri for prefix,uri in lxmlroot_respond.nsmap.iteritems() if prefix}
-            #For python3
-            #namespaces = {prefix:uri for prefix,uri in lxmlroot_respond.nsmap.items() if prefix}
+            namespaces = {prefix: uri for prefix, uri in lxmlroot_respond.nsmap.items() if prefix}
             namespaces["xmlns"]= "http://www.vmware.com/vcloud/v1.5"
             instance_id = 0
             for item in lxmlroot_respond.iterfind('xmlns:Item',namespaces):
@@ -6392,19 +6367,15 @@
         if "used_vlanIDs" not in self.persistent_info:
                 self.persistent_info["used_vlanIDs"] = {}
         else:
-            used_ids = self.persistent_info["used_vlanIDs"].values()
-            #For python3
-            #used_ids = list(self.persistent_info["used_vlanIDs"].values())
+            used_ids = list(self.persistent_info["used_vlanIDs"].values())
 
         for vlanID_range in self.config.get('vlanID_range'):
-            start_vlanid , end_vlanid = vlanID_range.split("-")
+            start_vlanid, end_vlanid = vlanID_range.split("-")
             if start_vlanid > end_vlanid:
                 raise vimconn.vimconnConflictException("Invalid vlan ID range {}".format(
                                                                         vlanID_range))
 
-            for id in xrange(int(start_vlanid), int(end_vlanid) + 1):
-            #For python3
-            #for id in range(int(start_vlanid), int(end_vlanid) + 1):
+            for id in range(int(start_vlanid), int(end_vlanid) + 1):
                 if id not in used_ids:
                     vlan_id = id
                     self.persistent_info["used_vlanIDs"][network_name] = vlan_id
diff --git a/RO-VIM-vmware/requirements.txt b/RO-VIM-vmware/requirements.txt
new file mode 100644
index 0000000..05a3ec1
--- /dev/null
+++ b/RO-VIM-vmware/requirements.txt
@@ -0,0 +1,25 @@
+##
+# Copyright VMware 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.
+##
+
+PyYAML
+requests
+netaddr
+pyvcloud==19.1.1
+pyvmomi
+progressbar
+prettytable
+# TODO py3 genisoimage
+git+https://osm.etsi.org/gerrit/osm/RO.git#egg=osm-ro&subdirectory=RO
diff --git a/RO-VIM-vmware/setup.py b/RO-VIM-vmware/setup.py
new file mode 100644
index 0000000..193102e
--- /dev/null
+++ b/RO-VIM-vmware/setup.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+##
+# Copyright VMware 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.
+##
+
+from setuptools import setup
+
+_name = "osm_rovim_vmware"
+
+README = """
+===========
+osm-rovim_vmware
+===========
+
+osm-ro pluging for vmware VIM
+"""
+
+setup(
+    name=_name,
+    description='OSM ro vim plugin for vmware',
+    long_description=README,
+    version_command=('git describe --match v* --tags --long --dirty', 'pep440-git-full'),
+    # version=VERSION,
+    # python_requires='>3.5.0',
+    author='ETSI OSM',
+    # TODO py3 author_email='',
+    maintainer='OSM_TECH@LIST.ETSI.ORG',  # TODO py3
+    # TODO py3 maintainer_email='',
+    url='https://osm.etsi.org/gitweb/?p=osm/RO.git;a=summary',
+    license='Apache 2.0',
+
+    packages=[_name],
+    include_package_data=True,
+    dependency_links=["git+https://osm.etsi.org/gerrit/osm/RO.git#egg=osm-ro"],
+    install_requires=[
+        "pyvcloud==19.1.1", "progressbar", "prettytable", "pyvmomi",
+        "requests", "netaddr", "PyYAML",
+        "osm-ro",
+    ],
+    setup_requires=['setuptools-version-command'],
+    entry_points={
+        'osm_rovim.plugins': ['rovim_vmware = osm_rovim_vmware.vimconn_vmware'],
+    },
+)
diff --git a/RO-VIM-vmware/stdeb.cfg b/RO-VIM-vmware/stdeb.cfg
new file mode 100644
index 0000000..ff50a2f
--- /dev/null
+++ b/RO-VIM-vmware/stdeb.cfg
@@ -0,0 +1,20 @@
+##
+# Copyright VMware 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.
+##
+
+[DEFAULT]
+X-Python3-Version : >= 3.5
+Depends3: python3-requests, python3-netaddr, python3-yaml, python3-osm-ro, python3-pip,
+          genisoimage, python3-progressbar, python3-prettytable, python3-pyvmomi
diff --git a/RO-VIM-vmware/tox.ini b/RO-VIM-vmware/tox.ini
new file mode 100644
index 0000000..efe01ef
--- /dev/null
+++ b/RO-VIM-vmware/tox.ini
@@ -0,0 +1,42 @@
+##
+# Copyright VMware 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.
+##
+
+[tox]
+envlist = py3
+toxworkdir={homedir}/.tox
+
+[testenv]
+basepython = python3
+install_command = python3 -m pip install -r requirements.txt -U {opts} {packages}
+# deps = -r{toxinidir}/test-requirements.txt
+commands=python3 -m unittest discover -v
+
+[testenv:flake8]
+basepython = python3
+deps = flake8
+commands = flake8 osm_rovim_vmware --max-line-length 120 \
+    --exclude .svn,CVS,.gz,.git,__pycache__,.tox,local,temp --ignore W291,W293,E226,W504
+
+[testenv:unittest]
+basepython = python3
+commands = python3 -m unittest discover -v osm_rovim_vmware/tests
+
+[testenv:build]
+basepython = python3
+deps = stdeb
+       setuptools-version-command
+commands = python3 setup.py --command-packages=stdeb.command bdist_deb
+
diff --git a/RO-client/Makefile b/RO-client/Makefile
new file mode 100644
index 0000000..e689ad6
--- /dev/null
+++ b/RO-client/Makefile
@@ -0,0 +1,25 @@
+# Copyright 2018 Telefonica S.A.
+#
+# 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.
+
+all: clean package
+
+clean:
+	rm -rf dist deb_dist osm_roclient-*.tar.gz osm_roclient.egg-info .eggs
+
+package:
+	python3 setup.py --command-packages=stdeb.command sdist_dsc
+	cp debian/python3-osm-roclient.postinst deb_dist/osm-roclient*/debian/
+	cd deb_dist/osm-roclient*/ && dpkg-buildpackage -rfakeroot -uc -us
+
diff --git a/RO-client/README.rst b/RO-client/README.rst
new file mode 100644
index 0000000..9b60216
--- /dev/null
+++ b/RO-client/README.rst
@@ -0,0 +1,20 @@
+ Copyright 2018 Telefonica S.A.
+ 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.
+
+============
+osm-roclient
+============
+
+osm-roclient is a client for interact with osm-ro server
+
diff --git a/RO-client/debian/python3-osm-roclient.postinst b/RO-client/debian/python3-osm-roclient.postinst
new file mode 100755
index 0000000..27c9044
--- /dev/null
+++ b/RO-client/debian/python3-osm-roclient.postinst
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+##
+# 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.
+##
+
+
+#configure arg-autocomplete for RO-client
+su $SUDO_USER -c 'activate-global-python-argcomplete --user'
+if ! su  $SUDO_USER -c 'grep -q bash_completion.d/python-argcomplete.sh ${HOME}/.bashrc'
+then
+    echo "    inserting .bash_completion.d/python-argcomplete.sh execution at .bashrc"
+    su $SUDO_USER -c 'echo ". ${HOME}/.bash_completion.d/python-argcomplete.sh" >> ~/.bashrc'
+fi
+
diff --git a/openmano b/RO-client/osm_roclient/roclient.py
similarity index 82%
rename from openmano
rename to RO-client/osm_roclient/roclient.py
index 13a93da..0e6d32c 100755
--- a/openmano
+++ b/RO-client/osm_roclient/roclient.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 # PYTHON_ARGCOMPLETE_OK
 
@@ -28,8 +28,8 @@
 """
 __author__ = "Alfonso Tierno, Gerardo Garcia, Pablo Montes"
 __date__ = "$09-oct-2014 09:09:48$"
-__version__ = "0.4.24-r534"
-version_date = "Nov 2018"
+__version__ = "0.5.0"
+version_date = "2019-010-04"
 
 from argcomplete.completers import FilesCompleter
 import os
@@ -41,24 +41,29 @@
 import logging
 #from jsonschema import validate as js_v, exceptions as js_e
 
-class ArgumentParserError(Exception): pass
 
-class OpenmanoCLIError(Exception): pass
+class ArgumentParserError(Exception):
+    pass
+
+
+class OpenmanoCLIError(Exception):
+    pass
+
 
 class ThrowingArgumentParser(argparse.ArgumentParser):
     def error(self, message):
-        print "Error: %s" %message
-        print
+        print("Error: {}".format(message))
+        print()
         self.print_usage()
         #self.print_help()
-        print
-        print "Type 'openmano -h' for help"
+        print()
+        print("Type 'openmano -h' for help")
         raise ArgumentParserError
 
 
 def config(args):
-    print "OPENMANO_HOST: %s" %mano_host
-    print "OPENMANO_PORT: %s" %mano_port
+    print("OPENMANO_HOST: {}".format(mano_host))
+    print("OPENMANO_PORT: {}".format(mano_port))
     if args.n:
         logger.debug("resolving tenant and datacenter names")
         mano_tenant_id = "None"
@@ -71,21 +76,22 @@
         mano_wim_name = "None"
         try:
             mano_tenant_id = _get_item_uuid("tenants", mano_tenant)
-            URLrequest = "http://%s:%s/openmano/tenants/%s" %(mano_host, mano_port, mano_tenant_id)
+            URLrequest = "http://{}:{}/openmano/tenants/{}".format(mano_host, mano_port, mano_tenant_id)
             mano_response = requests.get(URLrequest)
             logger.debug("openmano response: %s", mano_response.text )
             content = mano_response.json()
             mano_tenant_name = content["tenant"]["name"]
-            URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, mano_tenant_id, mano_datacenter)
+            URLrequest = "http://{}:{}/openmano/{}/datacenters/{}".format(mano_host, mano_port, mano_tenant_id,
+                                                                          mano_datacenter)
             mano_response = requests.get(URLrequest)
-            logger.debug("openmano response: %s", mano_response.text )
+            logger.debug("openmano response: %s", mano_response.text)
             content = mano_response.json()
             if "error" not in content:
                 mano_datacenter_id = content["datacenter"]["uuid"]
                 mano_datacenter_name = content["datacenter"]["name"]
 
             # WIM
-            URLrequest = "http://%s:%s/openmano/%s/wims/%s" % (
+            URLrequest = "http://{}:{}/openmano/{}/wims/{}".format(
             mano_host, mano_port, mano_tenant_id, mano_wim)
             mano_response = requests.get(URLrequest)
             logger.debug("openmano response: %s", mano_response.text)
@@ -96,49 +102,49 @@
 
         except OpenmanoCLIError:
             pass
-        print "OPENMANO_TENANT: %s" %mano_tenant
-        print "    Id: %s" %mano_tenant_id
-        print "    Name: %s" %mano_tenant_name
-        print "OPENMANO_DATACENTER: %s" %str (mano_datacenter)
-        print "    Id: %s" %mano_datacenter_id
-        print "    Name: %s" %mano_datacenter_name
+        print( "OPENMANO_TENANT: {}".format(mano_tenant))
+        print( "    Id: {}".format(mano_tenant_id))
+        print( "    Name: {}".format(mano_tenant_name))
+        print( "OPENMANO_DATACENTER: {}".format(mano_datacenter))
+        print( "    Id: {}".format(mano_datacenter_id))
+        print( "    Name: {}".format(mano_datacenter_name))
         # WIM
-        print "OPENMANO_WIM: %s" %str (mano_wim)
-        print "    Id: %s" %mano_wim_id
-        print "    Name: %s" %mano_wim_name
+        print( "OPENMANO_WIM: {}".format( (mano_wim)))
+        print( "    Id: {}".format(mano_wim_id))
+        print( "    Name: {}".format(mano_wim_name))
 
     else:
-        print "OPENMANO_TENANT: %s" %mano_tenant
-        print "OPENMANO_DATACENTER: %s" %str (mano_datacenter)
+        print("OPENMANO_TENANT: {}".format(mano_tenant))
+        print("OPENMANO_DATACENTER: {}".format(mano_datacenter))
         # WIM
-        print "OPENMANO_WIM: %s" %str (mano_wim)
+        print("OPENMANO_WIM: {}".format(mano_wim))
 
 def _print_verbose(mano_response, verbose_level=0):
     content = mano_response.json()
     result = 0 if mano_response.status_code==200 else mano_response.status_code
     if type(content)!=dict or len(content)!=1:
-        #print "Non expected format output"
-        print str(content)
+        # print("Non expected format output")
+        print(str(content))
         return result
 
-    val=content.values()[0]
+    val = next(iter(content.values()))
     if type(val)==str:
-        print val
+        print(val)
         return result
     elif type(val) == list:
         content_list = val
     elif type(val)==dict:
         content_list = [val]
     else:
-        #print "Non expected dict/list format output"
-        print str(content)
+        # print("Non expected dict/list format output"
+        print(str(content))
         return result
 
-    #print content_list
+    # print(content_list
     if verbose_level==None:
         verbose_level=0
     if verbose_level >= 3:
-        print yaml.safe_dump(content, indent=4, default_flow_style=False)
+        print(yaml.safe_dump(content, indent=4, default_flow_style=False))
         return result
 
     if mano_response.status_code == 200:
@@ -173,35 +179,33 @@
                         new_line=''
                     if content.get('description'):
                         myoutput += new_line + "  Description: {:20}".format(content['description'])
-            print myoutput
+            print(myoutput)
     else:
-        print content['error']['description']
+        print(content['error']['description'])
     return result
 
 def parser_json_yaml(file_name):
     try:
-        f = file(file_name, "r")
-        text = f.read()
-        f.close()
+        with open(file_name, "r") as f:
+            text = f.read()
     except Exception as e:
         return (False, str(e))
 
     #Read and parse file
     if file_name[-5:]=='.yaml' or file_name[-4:]=='.yml' or (file_name[-5:]!='.json' and '\t' not in text):
         try:
-            config = yaml.load(text)
+            config = yaml.load(text, Loader=yaml.SafeLoader)
         except yaml.YAMLError as exc:
             error_pos = ""
             if hasattr(exc, 'problem_mark'):
                 mark = exc.problem_mark
-                error_pos = " at line:%s column:%s" % (mark.line+1, mark.column+1)
+                error_pos = " at line:{} column:{}".format(mark.line+1, mark.column+1)
             return (False, "Error loading file '"+file_name+"' yaml format error" + error_pos)
     else: #json
         try:
             config = json.loads(text)
         except Exception as e:
             return (False, "Error loading file '"+file_name+"' json format error " + str(e) )
-
     return True, config
 
 def _load_file_or_yaml(content):
@@ -215,7 +219,7 @@
     if os.path.isfile(content):
         r,payload = parser_json_yaml(content)
         if not r:
-            print payload
+            print(payload)
             exit(-1)
     elif "{" in content or ":" in content:
         try:
@@ -224,23 +228,23 @@
             error_pos = ""
             if hasattr(exc, 'problem_mark'):
                 mark = exc.problem_mark
-                error_pos = " at position: (%s:%s)" % (mark.line+1, mark.column+1)
-            print "Error loading yaml/json text"+error_pos
+                error_pos = " at position: ({}:{})".format(mark.line+1, mark.column+1)
+            print("Error loading yaml/json text"+error_pos)
             exit (-1)
     else:
-        print "'%s' is neither a valid file nor a yaml/json content" % content
+        print("'{}' is neither a valid file nor a yaml/json content".format(content))
         exit(-1)
     return payload
 
 def _get_item_uuid(item, item_name_id, tenant=None):
     if tenant:
-        URLrequest = "http://%s:%s/openmano/%s/%s" %(mano_host, mano_port, tenant, item)
+        URLrequest = "http://{}:{}/openmano/{}/{}".format(mano_host, mano_port, tenant, item)
     else:
-        URLrequest = "http://%s:%s/openmano/%s" %(mano_host, mano_port, item)
+        URLrequest = "http://{}:{}/openmano/{}".format(mano_host, mano_port, item)
     mano_response = requests.get(URLrequest)
     logger.debug("openmano response: %s", mano_response.text )
     content = mano_response.json()
-    #print content
+    # print(content
     found = 0
     for i in content[item]:
         if i["uuid"] == item_name_id:
@@ -252,9 +256,9 @@
             uuid = i["uuid"]
             found += 1
     if found == 0:
-        raise OpenmanoCLIError("No %s found with name/uuid '%s'" %(item[:-1], item_name_id))
+        raise OpenmanoCLIError("No {} found with name/uuid '{}'".format(item[:-1], item_name_id))
     elif found > 1:
-        raise OpenmanoCLIError("%d %s found with name '%s'. uuid must be used" %(found, item, item_name_id))
+        raise OpenmanoCLIError("{} {} found with name '{}'. uuid must be used".format(found, item, item_name_id))
     return uuid
 #
 # def check_valid_uuid(uuid):
@@ -288,10 +292,11 @@
     return _get_item_uuid("wims", wim_name_id, tenant)
 
 def vnf_create(args):
-    #print "vnf-create",args
+    # print("vnf-create", args)
     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
     tenant = _get_tenant()
     myvnf = _load_file_or_yaml(args.file)
+
     api_version = ""
     if "vnfd:vnfd-catalog" in myvnf or "vnfd-catalog" in myvnf:
         api_version = "/v3"
@@ -313,7 +318,7 @@
 
     if args.name or args.description or args.image_path or args.image_name or args.image_checksum:
         # TODO, change this for API v3
-        # print args.name
+        # print(args.name
         try:
             if args.name:
                 vnfd['name'] = args.name
@@ -323,7 +328,7 @@
                 if args.image_path:
                     index = 0
                     for image_path_ in args.image_path.split(","):
-                        # print "image-path", image_path_
+                        # print("image-path", image_path_)
                         if api_version == "/v3":
                             if vdu_list[index].get("image"):
                                 vdu_list[index]['image'] = image_path_
@@ -376,7 +381,7 @@
                         else:
                             vdu_list[index]['image checksum'] = image_checksum_
                         index += 1
-        except (KeyError, TypeError), e:
+        except (KeyError, TypeError) as e:
             if str(e) == 'vnf':           error_pos= "missing field 'vnf'"
             elif str(e) == 'name':        error_pos= "missing field  'vnf':'name'"
             elif str(e) == 'description': error_pos= "missing field  'vnf':'description'"
@@ -386,44 +391,44 @@
             elif str(e) == 'image name':  error_pos= "missing field 'vnf':'VNFC'['image name']"
             elif str(e) == 'image checksum':  error_pos= "missing field 'vnf':'VNFC'['image checksum']"
             else:                       error_pos="wrong format"
-            print "Wrong VNF descriptor: " + error_pos
+            print("Wrong VNF descriptor: " + error_pos)
             return -1
     payload_req = json.dumps(myvnf)
 
-    #print payload_req
+    # print(payload_req
 
     URLrequest = "http://{}:{}/openmano{}/{}/{token}".format(mano_host, mano_port, api_version, tenant, token=token)
     logger.debug("openmano request: %s", payload_req)
-    mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
+    mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
     logger.debug("openmano response: %s", mano_response.text )
 
     return _print_verbose(mano_response, args.verbose)
 
 def vnf_list(args):
-    #print "vnf-list",args
+    # print("vnf-list",args
     if args.all:
         tenant = "any"
     else:
         tenant = _get_tenant()
     if args.name:
         toshow = _get_item_uuid("vnfs", args.name, tenant)
-        URLrequest = "http://%s:%s/openmano/%s/vnfs/%s" %(mano_host, mano_port, tenant, toshow)
+        URLrequest = "http://{}:{}/openmano/{}/vnfs/{}".format(mano_host, mano_port, tenant, toshow)
     else:
-        URLrequest = "http://%s:%s/openmano/%s/vnfs" %(mano_host, mano_port, tenant)
+        URLrequest = "http://{}:{}/openmano/{}/vnfs".format(mano_host, mano_port, tenant)
     mano_response = requests.get(URLrequest)
     logger.debug("openmano response: %s", mano_response.text )
     content = mano_response.json()
-    # print json.dumps(content, indent=4)
+    # print(json.dumps(content, indent=4)
     if args.verbose==None:
         args.verbose=0
     result = 0 if mano_response.status_code==200 else mano_response.status_code
     if mano_response.status_code == 200:
         if not args.name:
             if args.verbose >= 3:
-                print yaml.safe_dump(content, indent=4, default_flow_style=False)
+                print(yaml.safe_dump(content, indent=4, default_flow_style=False))
                 return result
             if len(content['vnfs']) == 0:
-                print "No VNFs were found."
+                print("No VNFs were found.")
                 return 404   # HTTP_Not_Found
             for vnf in content['vnfs']:
                 myoutput = "{:38} {:20}".format(vnf['uuid'], vnf['name'])
@@ -431,64 +436,64 @@
                     myoutput += " osm_id={:20}".format(vnf.get('osm_id'))
                 if args.verbose >= 1:
                     myoutput += " {}".format(vnf['created_at'])
-                print (myoutput)
+                print(myoutput)
                 if args.verbose >= 2:
-                    print ("  Description: {}".format(vnf['description']))
-                    # print ("  VNF descriptor file: {}".format(vnf['path']))
+                    print("  Description: {}".format(vnf['description']))
+                    # print("  VNF descriptor file: {}".format(vnf['path']))
         else:
             if args.verbose:
-                print yaml.safe_dump(content, indent=4, default_flow_style=False)
+                print(yaml.safe_dump(content, indent=4, default_flow_style=False))
                 return result
             vnf = content['vnf']
-            print ("{:38} {:20} osm_id={:20} {:20}".format(vnf['uuid'], vnf['name'], vnf.get('osm_id'),
-                                                           vnf['created_at']))
-            print ("  Description: {}".format(vnf['description']))
-            # print "  VNF descriptor file: %s" %vnf['path']
-            print ("  VMs:")
+            print("{:38} {:20} osm_id={:20} {:20}".format(vnf['uuid'], vnf['name'], vnf.get('osm_id'),
+                                                          vnf['created_at']), end=" ")
+            print("  Description: {}".format(vnf['description']))
+            # print(" VNF descriptor file: {}".format(vnf['path']))
+            print("  VMs:")
             for vm in vnf['VNFC']:
-                print ("    {:20} osm_id={:20} {}".format(vm['name'], vm.get('osm_id'), vm['description']))
+                print("    {:20} osm_id={:20} {}".format(vm['name'], vm.get('osm_id'), vm['description']))
             if len(vnf['nets']) > 0:
-                print ("  Internal nets:")
+                print("  Internal nets:")
                 for net in vnf['nets']:
-                    print ("    {:20} {}".format(net['name'], net['description']))
+                    print("    {:20} {}".format(net['name'], net['description']))
             if len(vnf['external-connections']) > 0:
-                print ("  External interfaces:")
+                print("  External interfaces:")
                 for interface in vnf['external-connections']:
-                    print ("    {:20} {:20} {:20} {:14}".format(
+                    print("    {:20} {:20} {:20} {:14}".format(
                         interface['external_name'], interface['vm_name'],
                         interface['internal_name'],
                         interface.get('vpci') if interface.get('vpci') else ""))
     else:
-        print content['error']['description']
+        print(content['error']['description'])
         if args.verbose:
-            print yaml.safe_dump(content, indent=4, default_flow_style=False)
+            print(yaml.safe_dump(content, indent=4, default_flow_style=False))
     return result
 
 def vnf_delete(args):
-    #print "vnf-delete",args
+    # print("vnf-delete",args
     if args.all:
         tenant = "any"
     else:
         tenant = _get_tenant()
     todelete = _get_item_uuid("vnfs", args.name, tenant=tenant)
     if not args.force:
-        r = raw_input("Delete VNF %s (y/N)? " %(todelete))
+        r = input("Delete VNF {} (y/N)? ".format(todelete))
         if  not (len(r)>0  and r[0].lower()=="y"):
             return 0
-    URLrequest = "http://%s:%s/openmano/%s/vnfs/%s" %(mano_host, mano_port, tenant, todelete)
+    URLrequest = "http://{}:{}/openmano/{}/vnfs/{}".format(mano_host, mano_port, tenant, todelete)
     mano_response = requests.delete(URLrequest)
     logger.debug("openmano response: %s", mano_response.text )
     result = 0 if mano_response.status_code==200 else mano_response.status_code
     content = mano_response.json()
-    #print json.dumps(content, indent=4)
+    # print(json.dumps(content, indent=4))
     if mano_response.status_code == 200:
-        print content['result']
+        print(content['result'])
     else:
-        print content['error']['description']
+        print(content['error']['description'])
     return result
 
 def scenario_create(args):
-    # print "scenario-create",args
+    # print("scenario-create",args
     tenant = _get_tenant()
     headers_req = {'content-type': 'application/yaml'}
     myscenario = _load_file_or_yaml(args.file)
@@ -515,9 +520,9 @@
     if args.description:
         nsd['description'] = args.description
     payload_req = yaml.safe_dump(myscenario, explicit_start=True, indent=4, default_flow_style=False, tags=False,
-                                 encoding='utf-8', allow_unicode=True)
+                                 allow_unicode=True)
 
-    # print payload_req
+    # print(payload_req
     URLrequest = "http://{host}:{port}/openmano{api}/{tenant}/{token}".format(
         host=mano_host, port=mano_port, api=api_version, tenant=tenant, token=token)
     logger.debug("openmano request: %s", payload_req)
@@ -526,20 +531,20 @@
     return _print_verbose(mano_response, args.verbose)
 
 def scenario_list(args):
-    #print "scenario-list",args
+    # print("scenario-list",args
     if args.all:
         tenant = "any"
     else:
         tenant = _get_tenant()
     if args.name:
         toshow = _get_item_uuid("scenarios", args.name, tenant)
-        URLrequest = "http://%s:%s/openmano/%s/scenarios/%s" %(mano_host, mano_port, tenant, toshow)
+        URLrequest = "http://{}:{}/openmano/{}/scenarios/{}".format(mano_host, mano_port, tenant, toshow)
     else:
-        URLrequest = "http://%s:%s/openmano/%s/scenarios" %(mano_host, mano_port, tenant)
+        URLrequest = "http://{}:{}/openmano/{}/scenarios".format(mano_host, mano_port, tenant)
     mano_response = requests.get(URLrequest)
     logger.debug("openmano response: %s", mano_response.text )
     content = mano_response.json()
-    #print json.dumps(content, indent=4)
+    # print(json.dumps(content, indent=4)
     if args.verbose==None:
         args.verbose=0
 
@@ -547,10 +552,10 @@
     if mano_response.status_code == 200:
         if not args.name:
             if args.verbose >= 3:
-                print yaml.safe_dump(content, indent=4, default_flow_style=False)
+                print( yaml.safe_dump(content, indent=4, default_flow_style=False))
                 return result
             if len(content['scenarios']) == 0:
-                print "No scenarios were found."
+                print( "No scenarios were found.")
                 return 404 #HTTP_Not_Found
             for scenario in content['scenarios']:
                 myoutput = "{:38} {:20}".format(scenario['uuid'], scenario['name'])
@@ -558,23 +563,23 @@
                     myoutput += " osm_id={:20}".format(scenario.get('osm_id'))
                 if args.verbose >= 1:
                     myoutput += " {}".format(scenario['created_at'])
-                print (myoutput)
+                print(myoutput)
                 if args.verbose >=2:
-                    print ("  Description: {}".format(scenario['description']))
+                    print("  Description: {}".format(scenario['description']))
         else:
             if args.verbose:
-                print yaml.safe_dump(content, indent=4, default_flow_style=False)
+                print(yaml.safe_dump(content, indent=4, default_flow_style=False))
                 return result
             scenario = content['scenario']
-            print ("{:38} {:20} osm_id={:20} {:20}".format(scenario['uuid'], scenario['name'], scenario.get('osm_id'),
-                                                           scenario['created_at']))
-            print ("  Description: {}".format(scenario['description']))
-            print ("  VNFs:")
+            print("{:38} {:20} osm_id={:20} {:20}".format(scenario['uuid'], scenario['name'], scenario.get('osm_id'),
+                                                          scenario['created_at']), end=" ")
+            print("  Description: {}".format(scenario['description']))
+            print("  VNFs:")
             for vnf in scenario['vnfs']:
-                print ("    {:38} {:20} vnf_index={} {}".format(vnf['vnf_id'], vnf['name'], vnf.get("member_vnf_index"),
+                print("    {:38} {:20} vnf_index={} {}".format(vnf['vnf_id'], vnf['name'], vnf.get("member_vnf_index"),
                                                                 vnf['description']))
             if len(scenario['nets']) > 0:
-                print ("  nets:")
+                print("  nets:")
                 for net in scenario['nets']:
                     description = net['description']
                     if not description:   # if description does not exist, description is "-". Valid for external and internal nets.
@@ -585,39 +590,39 @@
                     external = ""
                     if net["external"]:
                         external = " external"
-                    print ("    {:20} {:38} {:30}{}{}".format(net['name'], net['uuid'], description, vim_id, external))
+                    print("    {:20} {:38} {:30}{}{}".format(net['name'], net['uuid'], description, vim_id, external))
     else:
-        print (content['error']['description'])
+        print(content['error']['description'])
         if args.verbose:
-            print yaml.safe_dump(content, indent=4, default_flow_style=False)
+            print(yaml.safe_dump(content, indent=4, default_flow_style=False))
     return result
 
 def scenario_delete(args):
-    #print "scenario-delete",args
+    # print("scenario-delete",args
     if args.all:
         tenant = "any"
     else:
         tenant = _get_tenant()
     todelete = _get_item_uuid("scenarios", args.name, tenant=tenant)
     if not args.force:
-        r = raw_input("Delete scenario %s (y/N)? " %(args.name))
+        r = input("Delete scenario {} (y/N)? ".format(args.name))
         if  not (len(r)>0  and r[0].lower()=="y"):
             return 0
-    URLrequest = "http://%s:%s/openmano/%s/scenarios/%s" %(mano_host, mano_port, tenant, todelete)
+    URLrequest = "http://{}:{}/openmano/{}/scenarios/{}".format(mano_host, mano_port, tenant, todelete)
     mano_response = requests.delete(URLrequest)
     logger.debug("openmano response: %s", mano_response.text )
     result = 0 if mano_response.status_code==200 else mano_response.status_code
     content = mano_response.json()
-    #print json.dumps(content, indent=4)
+    # print(json.dumps(content, indent=4)
     if mano_response.status_code == 200:
-        print content['result']
+        print( content['result'])
     else:
-        print content['error']['description']
+        print( content['error']['description'])
     return result
 
 def scenario_deploy(args):
-    print "This command is deprecated, use 'openmano instance-scenario-create --scenario %s --name %s' instead!!!" % (args.scenario, args.name)
-    print
+    print("This command is deprecated, use 'openmano instance-scenario-create --scenario {} --name {}' instead!!!".format(args.scenario, args.name))
+    print()
     args.file = None
     args.netmap_use = None
     args.netmap_create = None
@@ -625,7 +630,7 @@
     args.keypair_auto = None
     return instance_create(args)
 
-#     #print "scenario-deploy",args
+#     # print("scenario-deploy",args
 #     headers_req = {'content-type': 'application/json'}
 #     action = {}
 #     actionCmd="start"
@@ -641,9 +646,9 @@
 #     if args.description:
 #         action[actionCmd]["description"] = args.description
 #     payload_req = json.dumps(action, indent=4)
-#     #print payload_req
+#     # print(payload_req
 #
-#     URLrequest = "http://%s:%s/openmano/%s/scenarios/%s/action" %(mano_host, mano_port, mano_tenant, args.scenario)
+#     URLrequest = "http://{}:{}/openmano/{}/scenarios/{}/action".format(mano_host, mano_port, mano_tenant, args.scenario)
 #     logger.debug("openmano request: %s", payload_req)
 #     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
 #     logger.debug("openmano response: %s", mano_response.text )
@@ -652,47 +657,47 @@
 #
 #     result = 0 if mano_response.status_code==200 else mano_response.status_code
 #     content = mano_response.json()
-#     #print json.dumps(content, indent=4)
+#     # print(json.dumps(content, indent=4))
 #     if args.verbose >= 3:
-#         print yaml.safe_dump(content, indent=4, default_flow_style=False)
+#         print(yaml.safe_dump(content, indent=4, default_flow_style=False))
 #         return result
 #
 #     if mano_response.status_code == 200:
-#         myoutput = "%s %s" %(content['uuid'].ljust(38),content['name'].ljust(20))
+#         myoutput = "{} {}".format(content['uuid'].ljust(38),content['name'].ljust(20))
 #         if args.verbose >=1:
-#             myoutput = "%s %s" %(myoutput, content['created_at'].ljust(20))
+#             myoutput = "{} {}".format(myoutput, content['created_at'].ljust(20))
 #         if args.verbose >=2:
-#             myoutput = "%s %s %s" %(myoutput, content['description'].ljust(30))
-#         print myoutput
-#         print ""
-#         print "To check the status, run the following command:"
-#         print "openmano instance-scenario-list <instance_id>"
+#             myoutput = "{} {} {}".format(myoutput, content['description'].ljust(30))
+#         print(myoutput)
+#         print("")
+#         print("To check the status, run the following command:")
+#         print("openmano instance-scenario-list <instance_id>"
 #     else:
-#         print content['error']['description']
+#         print(content['error']['description'])
 #     return result
 
 def scenario_verify(args):
-    #print "scenario-verify",args
+    # print("scenario-verify",args)
     tenant = _get_tenant()
     headers_req = {'content-type': 'application/json'}
     action = {}
     action["verify"] = {}
     action["verify"]["instance_name"] = "scen-verify-return5"
     payload_req = json.dumps(action, indent=4)
-    #print payload_req
+    # print(payload_req)
 
-    URLrequest = "http://%s:%s/openmano/%s/scenarios/%s/action" %(mano_host, mano_port, tenant, args.scenario)
+    URLrequest = "http://{}:{}/openmano/{}/scenarios/{}/action".format(mano_host, mano_port, tenant, args.scenario)
     logger.debug("openmano request: %s", payload_req)
     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
     logger.debug("openmano response: %s", mano_response.text )
 
     result = 0 if mano_response.status_code==200 else mano_response.status_code
     content = mano_response.json()
-    #print json.dumps(content, indent=4)
+    # print(json.dumps(content, indent=4))
     if mano_response.status_code == 200:
-        print content['result']
+        print(content['result'])
     else:
-        print content['error']['description']
+        print(content['error']['description'])
     return result
 
 def instance_create(args):
@@ -721,7 +726,7 @@
     if args.scenario != None:
         scenario = args.scenario
     if not scenario:
-        print "you must provide a scenario in the file descriptor or with --scenario"
+        print("you must provide a scenario in the file descriptor or with --scenario")
         return -1
     if isinstance(scenario, str):
         myInstance["instance"]["scenario"] = _get_item_uuid("scenarios", scenario, tenant)
@@ -733,7 +738,7 @@
             for net_comma in net_comma_list:
                 net_tuple = net_comma.split("=")
                 if len(net_tuple) != 2:
-                    print "error at netmap-use. Expected net-scenario=net-datacenter. (%s)?" % net_comma
+                    print("error at netmap-use. Expected net-scenario=net-datacenter. ({})?".format(net_comma))
                     return
                 net_scenario   = net_tuple[0].strip()
                 net_datacenter = net_tuple[1].strip()
@@ -756,7 +761,8 @@
                     net_scenario   = net_tuple[0].strip()
                     net_datacenter = net_tuple[1].strip()
                 else:
-                    print "error at netmap-create. Expected net-scenario=net-datacenter or net-scenario. (%s)?" % net_comma
+                    print("error at netmap-create. Expected net-scenario=net-datacenter or net-scenario. ({})?".format(
+                        net_comma))
                     return
                 if net_scenario not in myInstance["instance"]["networks"]:
                     myInstance["instance"]["networks"][net_scenario] = {}
@@ -791,10 +797,10 @@
                     with open(home+'/.ssh/'+file, 'r') as f:
                         keys.append(f.read())
             if not keys:
-                print "Cannot obtain any public ssh key from '{}'. Try not using --keymap-auto".format(home+'/.ssh')
+                print("Cannot obtain any public ssh key from '{}'. Try not using --keymap-auto".format(home+'/.ssh'))
                 return 1
         except Exception as e:
-            print "Cannot obtain any public ssh key. Error '{}'. Try not using --keymap-auto".format(str(e))
+            print("Cannot obtain any public ssh key. Error '{}'. Try not using --keymap-auto".format(str(e)))
             return 1
 
         if "cloud-config" not in myInstance["instance"]:
@@ -807,9 +813,10 @@
                 cloud_config["users"] = []
             cloud_config["users"].append({"name": user, "key-pairs": keys })
 
-    payload_req = yaml.safe_dump(myInstance, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True)
+    payload_req = yaml.safe_dump(myInstance, explicit_start=True, indent=4, default_flow_style=False, tags=False,
+                                 allow_unicode=True)
     logger.debug("openmano request: %s", payload_req)
-    URLrequest = "http://%s:%s/openmano/%s/instances" %(mano_host, mano_port, tenant)
+    URLrequest = "http://{}:{}/openmano/{}/instances".format(mano_host, mano_port, tenant)
     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
     logger.debug("openmano response: %s", mano_response.text )
     if args.verbose==None:
@@ -817,9 +824,9 @@
 
     result = 0 if mano_response.status_code==200 else mano_response.status_code
     content = mano_response.json()
-    #print json.dumps(content, indent=4)
+    # print(json.dumps(content, indent=4))
     if args.verbose >= 3:
-        print yaml.safe_dump(content, indent=4, default_flow_style=False)
+        print(yaml.safe_dump(content, indent=4, default_flow_style=False))
         return result
 
     if mano_response.status_code == 200:
@@ -828,26 +835,26 @@
             myoutput = "{} {:20}".format(myoutput, content['created_at'])
         if args.verbose >=2:
             myoutput = "{} {:30}".format(myoutput, content['description'])
-        print myoutput
+        print(myoutput)
     else:
-        print content['error']['description']
+        print(content['error']['description'])
     return result
 
 def instance_scenario_list(args):
-    #print "instance-scenario-list",args
+    # print("instance-scenario-list",args)
     if args.all:
         tenant = "any"
     else:
         tenant = _get_tenant()
     if args.name:
         toshow = _get_item_uuid("instances", args.name, tenant)
-        URLrequest = "http://%s:%s/openmano/%s/instances/%s" %(mano_host, mano_port, tenant, toshow)
+        URLrequest = "http://{}:{}/openmano/{}/instances/{}".format(mano_host, mano_port, tenant, toshow)
     else:
-        URLrequest = "http://%s:%s/openmano/%s/instances" %(mano_host, mano_port, tenant)
+        URLrequest = "http://{}:{}/openmano/{}/instances".format(mano_host, mano_port, tenant)
     mano_response = requests.get(URLrequest)
     logger.debug("openmano response: %s", mano_response.text )
     content = mano_response.json()
-    #print json.dumps(content, indent=4)
+    # print(json.dumps(content, indent=4)
     if args.verbose==None:
         args.verbose=0
 
@@ -855,57 +862,57 @@
     if mano_response.status_code == 200:
         if not args.name:
             if args.verbose >= 3:
-                print yaml.safe_dump(content, indent=4, default_flow_style=False)
+                print(yaml.safe_dump(content, indent=4, default_flow_style=False))
                 return result
             if len(content['instances']) == 0:
-                print "No scenario instances were found."
+                print("No scenario instances were found.")
                 return result
             for instance in content['instances']:
                 myoutput = "{:38} {:20}".format(instance['uuid'], instance['name'])
                 if args.verbose >=1:
                     myoutput = "{} {:20}".format(myoutput, instance['created_at'])
-                print myoutput
+                print(myoutput)
                 if args.verbose >=2:
-                    print "Description: %s" %instance['description']
+                    print("Description: {}".format(instance['description']))
         else:
             if args.verbose:
-                print yaml.safe_dump(content, indent=4, default_flow_style=False)
+                print(yaml.safe_dump(content, indent=4, default_flow_style=False))
                 return result
             instance = content
-            print ("{:38} {:20} {:20}".format(instance['uuid'],instance['name'],instance['created_at']))
-            print ("Description: %s" %instance['description'])
-            print ("Template scenario id: {}".format(instance['scenario_id']))
-            print ("Template scenario name: {}".format(instance['scenario_name']))
-            print ("---------------------------------------")
-            print ("VNF instances: {}".format(len(instance['vnfs'])))
+            print("{:38} {:20} {:20}".format(instance['uuid'],instance['name'],instance['created_at']))
+            print("Description: {}".format(instance['description']))
+            print("Template scenario id: {}".format(instance['scenario_id']))
+            print("Template scenario name: {}".format(instance['scenario_name']))
+            print("---------------------------------------")
+            print("VNF instances: {}".format(len(instance['vnfs'])))
             for vnf in instance['vnfs']:
-                #print "    %s %s Template vnf name: %s Template vnf id: %s" %(vnf['uuid'].ljust(38), vnf['name'].ljust(20), vnf['vnf_name'].ljust(20), vnf['vnf_id'].ljust(38))
-                print ("    {:38} {:20} Template vnf id: {:38}".format(vnf['uuid'], vnf['vnf_name'], vnf['vnf_id']))
+                # print("    {} {} Template vnf name: {} Template vnf id: {}".format(vnf['uuid'].ljust(38), vnf['name'].ljust(20), vnf['vnf_name'].ljust(20), vnf['vnf_id'].ljust(38))
+                print("    {:38} {:20} Template vnf id: {:38}".format(vnf['uuid'], vnf['vnf_name'], vnf['vnf_id']))
             if len(instance['nets'])>0:
-                print "---------------------------------------"
-                print "Internal nets:"
+                print("---------------------------------------")
+                print("Internal nets:")
                 for net in instance['nets']:
                     if net['created']:
-                        print ("    {:38} {:12} VIM ID: {}".format(net['uuid'], net['status'], net['vim_net_id']))
-                print "---------------------------------------"
-                print "External nets:"
+                        print("    {:38} {:12} VIM ID: {}".format(net['uuid'], net['status'], net['vim_net_id']))
+                print("---------------------------------------")
+                print("External nets:")
                 for net in instance['nets']:
                     if not net['created']:
-                        print ("    {:38} {:12} VIM ID: {}".format(net['uuid'], net['status'], net['vim_net_id']))
-            print ("---------------------------------------")
-            print ("VM instances:")
+                        print("    {:38} {:12} VIM ID: {}".format(net['uuid'], net['status'], net['vim_net_id']))
+            print("---------------------------------------")
+            print("VM instances:")
             for vnf in instance['vnfs']:
                 for vm in vnf['vms']:
-                    print ("    {:38} {:20} {:20} {:12} VIM ID: {}".format(vm['uuid'], vnf['vnf_name'], vm['name'],
-                                                                           vm['status'], vm['vim_vm_id']))
+                    print("    {:38} {:20} {:20} {:12} VIM ID: {}".format(vm['uuid'], vnf['vnf_name'], vm['name'],
+                                                                          vm['status'], vm['vim_vm_id']))
     else:
-        print content['error']['description']
+        print(content['error']['description'])
         if args.verbose:
-            print yaml.safe_dump(content, indent=4, default_flow_style=False)
+            print(yaml.safe_dump(content, indent=4, default_flow_style=False))
     return result
 
 def instance_scenario_status(args):
-    print "instance-scenario-status"
+    print("instance-scenario-status")
     return 0
 
 def instance_scenario_delete(args):
@@ -914,21 +921,21 @@
     else:
         tenant = _get_tenant()
     todelete = _get_item_uuid("instances", args.name, tenant=tenant)
-    #print "instance-scenario-delete",args
+    # print("instance-scenario-delete",args)
     if not args.force:
-        r = raw_input("Delete scenario instance %s (y/N)? " %(args.name))
+        r = input("Delete scenario instance {} (y/N)? ".format(args.name))
         if  not (len(r)>0  and r[0].lower()=="y"):
             return
-    URLrequest = "http://%s:%s/openmano/%s/instances/%s" %(mano_host, mano_port, tenant, todelete)
+    URLrequest = "http://{}:{}/openmano/{}/instances/{}".format(mano_host, mano_port, tenant, todelete)
     mano_response = requests.delete(URLrequest)
     logger.debug("openmano response: %s", mano_response.text )
     result = 0 if mano_response.status_code==200 else mano_response.status_code
     content = mano_response.json()
-    #print json.dumps(content, indent=4)
+    # print(json.dumps(content, indent=4))
     if mano_response.status_code == 200:
-        print content['result']
+        print(content['result'])
     else:
-        print content['error']['description']
+        print(content['error']['description'])
     return result
 
 def get_action(args):
@@ -954,7 +961,7 @@
     return _print_verbose(mano_response, args.verbose)
 
 def instance_scenario_action(args):
-    #print "instance-scenario-action", args
+    # print("instance-scenario-action", args)
     tenant = _get_tenant()
     toact = _get_item_uuid("instances", args.name, tenant=tenant)
     action={}
@@ -966,33 +973,33 @@
 
     headers_req = {'content-type': 'application/json'}
     payload_req = json.dumps(action, indent=4)
-    URLrequest = "http://%s:%s/openmano/%s/instances/%s/action" %(mano_host, mano_port, tenant, toact)
+    URLrequest = "http://{}:{}/openmano/{}/instances/{}/action".format(mano_host, mano_port, tenant, toact)
     logger.debug("openmano request: %s", payload_req)
     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
     logger.debug("openmano response: %s", mano_response.text )
     result = 0 if mano_response.status_code==200 else mano_response.status_code
     content = mano_response.json()
-    # print json.dumps(content, indent=4)
+    # print(json.dumps(content, indent=4))
     if mano_response.status_code == 200:
         if args.verbose:
-            print yaml.safe_dump(content, indent=4, default_flow_style=False)
+            print(yaml.safe_dump(content, indent=4, default_flow_style=False))
             return result
         if "instance_action_id" in content:
             print("instance_action_id={}".format(content["instance_action_id"]))
         else:
-            for uuid,c in content.iteritems():
-                print ("{:38} {:20} {:20}".format(uuid, c.get('name'), c.get('description')))
+            for uuid,c in content.items():
+                print("{:38} {:20} {:20}".format(uuid, c.get('name'), c.get('description')))
     else:
-        print content['error']['description']
+        print(content['error']['description'])
     return result
 
 
 def instance_vnf_list(args):
-    print "instance-vnf-list"
+    print("instance-vnf-list")
     return 0
 
 def instance_vnf_status(args):
-    print "instance-vnf-status"
+    print("instance-vnf-status")
     return 0
 
 def tenant_create(args):
@@ -1002,21 +1009,21 @@
         tenant_dict["description"] = args.description
     payload_req = json.dumps( {"tenant": tenant_dict })
 
-    #print payload_req
+    # print(payload_req)
 
-    URLrequest = "http://%s:%s/openmano/tenants" %(mano_host, mano_port)
+    URLrequest = "http://{}:{}/openmano/tenants".format(mano_host, mano_port)
     logger.debug("openmano request: %s", payload_req)
     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
     logger.debug("openmano response: %s", mano_response.text )
     return _print_verbose(mano_response, args.verbose)
 
 def tenant_list(args):
-    #print "tenant-list",args
+    # print("tenant-list",args)
     if args.name:
         toshow = _get_item_uuid("tenants", args.name)
-        URLrequest = "http://%s:%s/openmano/tenants/%s" %(mano_host, mano_port, toshow)
+        URLrequest = "http://{}:{}/openmano/tenants/{}".format(mano_host, mano_port, toshow)
     else:
-        URLrequest = "http://%s:%s/openmano/tenants" %(mano_host, mano_port)
+        URLrequest = "http://{}:{}/openmano/tenants".format(mano_host, mano_port)
     mano_response = requests.get(URLrequest)
     logger.debug("openmano response: %s", mano_response.text )
     if args.verbose==None:
@@ -1026,22 +1033,22 @@
     return _print_verbose(mano_response, args.verbose)
 
 def tenant_delete(args):
-    #print "tenant-delete",args
+    # print("tenant-delete",args)
     todelete = _get_item_uuid("tenants", args.name)
     if not args.force:
-        r = raw_input("Delete tenant %s (y/N)? " %(args.name))
+        r = input("Delete tenant {} (y/N)? ".format(args.name))
         if  not (len(r)>0  and r[0].lower()=="y"):
             return 0
-    URLrequest = "http://%s:%s/openmano/tenants/%s" %(mano_host, mano_port, todelete)
+    URLrequest = "http://{}:{}/openmano/tenants/{}".format(mano_host, mano_port, todelete)
     mano_response = requests.delete(URLrequest)
     logger.debug("openmano response: %s", mano_response.text )
     result = 0 if mano_response.status_code==200 else mano_response.status_code
     content = mano_response.json()
-    #print json.dumps(content, indent=4)
+    # print(json.dumps(content, indent=4))
     if mano_response.status_code == 200:
-        print content['result']
+        print(content['result'])
     else:
-        print content['error']['description']
+        print(content['error']['description'])
     return result
 
 def datacenter_attach(args):
@@ -1063,9 +1070,9 @@
 
     payload_req = json.dumps( {"datacenter": datacenter_dict })
 
-    #print payload_req
+    # print(payload_req)
 
-    URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, tenant, datacenter)
+    URLrequest = "http://{}:{}/openmano/{}/datacenters/{}".format(mano_host, mano_port, tenant, datacenter)
     logger.debug("openmano request: %s", payload_req)
     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
     logger.debug("openmano response: %s", mano_response.text )
@@ -1075,7 +1082,7 @@
         content = mano_response.json()
         if "already in use for  'name'" in content['error']['description'] and \
                 "to database vim_tenants table" in content['error']['description']:
-            print "Try to specify a different name with --vim-tenant-name"
+            print("Try to specify a different name with --vim-tenant-name")
     return result
 
 
@@ -1100,9 +1107,9 @@
         datacenter_dict["config"] = _load_file_or_yaml(args.config)
     payload_req = json.dumps({"datacenter": datacenter_dict})
 
-    # print payload_req
+    # print(payload_req)
 
-    URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" % (mano_host, mano_port, tenant, datacenter)
+    URLrequest = "http://{}:{}/openmano/{}/datacenters/{}".format(mano_host, mano_port, tenant, datacenter)
     logger.debug("openmano request: %s", payload_req)
     mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
     logger.debug("openmano response: %s", mano_response.text)
@@ -1117,16 +1124,16 @@
         tenant = _get_tenant()
     datacenter = _get_datacenter(args.name, tenant)
     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
-    URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, tenant, datacenter)
+    URLrequest = "http://{}:{}/openmano/{}/datacenters/{}".format(mano_host, mano_port, tenant, datacenter)
     mano_response = requests.delete(URLrequest, headers=headers_req)
     logger.debug("openmano response: %s", mano_response.text )
     content = mano_response.json()
-    #print json.dumps(content, indent=4)
+    # print(json.dumps(content, indent=4))
     result = 0 if mano_response.status_code==200 else mano_response.status_code
     if mano_response.status_code == 200:
-        print content['result']
+        print(content['result'])
     else:
-        print content['error']['description']
+        print(content['error']['description'])
     return result
 
 def datacenter_create(args):
@@ -1148,43 +1155,43 @@
         datacenter_dict['config']['sdn-controller'] = sdn_controller
     payload_req = json.dumps( {"datacenter": datacenter_dict })
 
-    #print payload_req
+    # print(payload_req)
 
-    URLrequest = "http://%s:%s/openmano/datacenters" %(mano_host, mano_port)
+    URLrequest = "http://{}:{}/openmano/datacenters".format(mano_host, mano_port)
     logger.debug("openmano request: %s", payload_req)
     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
     logger.debug("openmano response: %s", mano_response.text )
     return _print_verbose(mano_response, args.verbose)
 
 def datacenter_delete(args):
-    #print "datacenter-delete",args
+    # print("datacenter-delete",args)
     todelete = _get_item_uuid("datacenters", args.name, "any")
     if not args.force:
-        r = raw_input("Delete datacenter %s (y/N)? " %(args.name))
+        r = input("Delete datacenter {} (y/N)? ".format(args.name))
         if  not (len(r)>0  and r[0].lower()=="y"):
             return 0
-    URLrequest = "http://%s:%s/openmano/datacenters/%s" %(mano_host, mano_port, todelete)
+    URLrequest = "http://{}:{}/openmano/datacenters/{}".format(mano_host, mano_port, todelete)
     mano_response = requests.delete(URLrequest)
     logger.debug("openmano response: %s", mano_response.text )
     result = 0 if mano_response.status_code==200 else mano_response.status_code
     content = mano_response.json()
-    #print json.dumps(content, indent=4)
+    # print(json.dumps(content, indent=4))
     if mano_response.status_code == 200:
-        print content['result']
+        print(content['result'])
     else:
-        print content['error']['description']
+        print(content['error']['description'])
     return result
 
 
 def datacenter_list(args):
-    #print "datacenter-list",args
+    # print("datacenter-list",args)
     tenant='any' if args.all else _get_tenant()
 
     if args.name:
         toshow = _get_item_uuid("datacenters", args.name, tenant)
-        URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, tenant, toshow)
+        URLrequest = "http://{}:{}/openmano/{}/datacenters/{}".format(mano_host, mano_port, tenant, toshow)
     else:
-        URLrequest = "http://%s:%s/openmano/%s/datacenters" %(mano_host, mano_port, tenant)
+        URLrequest = "http://{}:{}/openmano/{}/datacenters".format(mano_host, mano_port, tenant)
     mano_response = requests.get(URLrequest)
     logger.debug("openmano response: %s", mano_response.text )
     if args.verbose==None:
@@ -1206,7 +1213,7 @@
     payload_req = json.dumps({"sdn_port_mapping": sdn_port_mapping})
 
     # read
-    URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/sdn_mapping" % (mano_host, mano_port, tenant, datacenter)
+    URLrequest = "http://{}:{}/openmano/{}/datacenters/{}/sdn_mapping".format(mano_host, mano_port, tenant, datacenter)
     mano_response = requests.get(URLrequest)
     logger.debug("openmano response: %s", mano_response.text)
     port_mapping = mano_response.json()
@@ -1215,19 +1222,19 @@
         raise OpenmanoCLIError("openmano client error: {}".format(port_mapping['error']['description']))
     if len(port_mapping["sdn_port_mapping"]["ports_mapping"]) > 0:
         if not args.force:
-            r = raw_input("Datacenter %s already contains a port mapping. Overwrite? (y/N)? " % (datacenter))
+            r = input("Datacenter {} already contains a port mapping. Overwrite? (y/N)? ".format(datacenter))
             if not (len(r) > 0 and r[0].lower() == "y"):
                 return 0
 
         # clear
-        URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/sdn_mapping" % (mano_host, mano_port, tenant, datacenter)
+        URLrequest = "http://{}:{}/openmano/{}/datacenters/{}/sdn_mapping".format(mano_host, mano_port, tenant, datacenter)
         mano_response = requests.delete(URLrequest)
         logger.debug("openmano response: %s", mano_response.text)
         if mano_response.status_code != 200:
             return _print_verbose(mano_response, args.verbose)
 
     # set
-    URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/sdn_mapping" % (mano_host, mano_port, tenant, datacenter)
+    URLrequest = "http://{}:{}/openmano/{}/datacenters/{}/sdn_mapping".format(mano_host, mano_port, tenant, datacenter)
     logger.debug("openmano request: %s", payload_req)
     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
     logger.debug("openmano response: %s", mano_response.text)
@@ -1238,7 +1245,7 @@
     tenant = _get_tenant()
     datacenter = _get_datacenter(args.name, tenant)
 
-    URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/sdn_mapping" % (mano_host, mano_port, tenant, datacenter)
+    URLrequest = "http://{}:{}/openmano/{}/datacenters/{}/sdn_mapping".format(mano_host, mano_port, tenant, datacenter)
     mano_response = requests.get(URLrequest)
     logger.debug("openmano response: %s", mano_response.text)
 
@@ -1250,11 +1257,11 @@
     datacenter = _get_datacenter(args.name, tenant)
 
     if not args.force:
-        r = raw_input("Clean SDN port mapping for datacenter %s (y/N)? " %(datacenter))
+        r = input("Clean SDN port mapping for datacenter {} (y/N)? ".format(datacenter))
         if not (len(r) > 0 and r[0].lower() == "y"):
             return 0
 
-    URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/sdn_mapping" % (mano_host, mano_port, tenant, datacenter)
+    URLrequest = "http://{}:{}/openmano/{}/datacenters/{}/sdn_mapping".format(mano_host, mano_port, tenant, datacenter)
     mano_response = requests.delete(URLrequest)
     logger.debug("openmano response: %s", mano_response.text)
 
@@ -1288,9 +1295,9 @@
 
     payload_req = json.dumps({"sdn_controller": controller_dict})
 
-    # print payload_req
+    # print(payload_req)
 
-    URLrequest = "http://%s:%s/openmano/%s/sdn_controllers" % (mano_host, mano_port, tenant)
+    URLrequest = "http://{}:{}/openmano/{}/sdn_controllers".format(mano_host, mano_port, tenant)
     logger.debug("openmano request: %s", payload_req)
     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
     logger.debug("openmano response: %s", mano_response.text)
@@ -1325,14 +1332,14 @@
         raise OpenmanoCLIError("At least one parameter must be edited")
 
     if not args.force:
-        r = raw_input("Update SDN controller {} (y/N)? ".format(args.name))
+        r = input("Update SDN controller {} (y/N)? ".format(args.name))
         if not (len(r) > 0 and r[0].lower() == "y"):
             return 0
 
     payload_req = json.dumps({"sdn_controller": controller_dict})
-    # print payload_req
+    # print(payload_req)
 
-    URLrequest = "http://%s:%s/openmano/%s/sdn_controllers/%s" % (mano_host, mano_port, tenant, controller_uuid)
+    URLrequest = "http://{}:{}/openmano/{}/sdn_controllers/{}".format(mano_host, mano_port, tenant, controller_uuid)
     logger.debug("openmano request: %s", payload_req)
     mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
     logger.debug("openmano response: %s", mano_response.text)
@@ -1346,10 +1353,10 @@
 
     if args.name:
         toshow = _get_item_uuid("sdn_controllers", args.name, tenant)
-        URLrequest = "http://%s:%s/openmano/%s/sdn_controllers/%s" %(mano_host, mano_port, tenant, toshow)
+        URLrequest = "http://{}:{}/openmano/{}/sdn_controllers/{}".format(mano_host, mano_port, tenant, toshow)
     else:
-        URLrequest = "http://%s:%s/openmano/%s/sdn_controllers" %(mano_host, mano_port, tenant)
-    #print URLrequest
+        URLrequest = "http://{}:{}/openmano/{}/sdn_controllers".format(mano_host, mano_port, tenant)
+    # print(URLrequest)
     mano_response = requests.get(URLrequest)
     logger.debug("openmano response: %s", mano_response.text )
     if args.verbose==None:
@@ -1366,23 +1373,23 @@
     controller_uuid = _get_item_uuid("sdn_controllers", args.name, tenant)
 
     if not args.force:
-        r = raw_input("Delete SDN controller %s (y/N)? " % (args.name))
+        r = input("Delete SDN controller {} (y/N)? ".format(args.name))
         if not (len(r) > 0 and r[0].lower() == "y"):
             return 0
 
-    URLrequest = "http://%s:%s/openmano/%s/sdn_controllers/%s" % (mano_host, mano_port, tenant, controller_uuid)
+    URLrequest = "http://{}:{}/openmano/{}/sdn_controllers/{}".format(mano_host, mano_port, tenant, controller_uuid)
     mano_response = requests.delete(URLrequest)
     logger.debug("openmano response: %s", mano_response.text)
     return _print_verbose(mano_response, args.verbose)
 
 def vim_action(args):
-    #print "datacenter-net-action",args
+    # print("datacenter-net-action",args)
     tenant = _get_tenant()
     datacenter = _get_datacenter(args.datacenter, tenant)
     if args.verbose==None:
         args.verbose=0
     if args.action=="list":
-        URLrequest = "http://%s:%s/openmano/%s/vim/%s/%ss" %(mano_host, mano_port, tenant, datacenter, args.item)
+        URLrequest = "http://{}:{}/openmano/{}/vim/{}/{}s".format(mano_host, mano_port, tenant, datacenter, args.item)
         if args.name!=None:
             args.verbose += 1
             URLrequest += "/" + args.name
@@ -1390,16 +1397,16 @@
         logger.debug("openmano response: %s", mano_response.text )
         return _print_verbose(mano_response, args.verbose)
     elif args.action=="delete":
-        URLrequest = "http://%s:%s/openmano/%s/vim/%s/%ss/%s" %(mano_host, mano_port, tenant, datacenter, args.item, args.name)
+        URLrequest = "http://{}:{}/openmano/{}/vim/{}/{}s/{}".format(mano_host, mano_port, tenant, datacenter, args.item, args.name)
         mano_response = requests.delete(URLrequest)
         logger.debug("openmano response: %s", mano_response.text )
         result = 0 if mano_response.status_code==200 else mano_response.status_code
         content = mano_response.json()
-        #print json.dumps(content, indent=4)
+        # print(json.dumps(content, indent=4))
         if mano_response.status_code == 200:
-            print content['result']
+            print(content['result'])
         else:
-            print content['error']['description']
+            print(content['error']['description'])
         return result
     elif args.action=="create":
         headers_req = {'content-type': 'application/yaml'}
@@ -1421,11 +1428,12 @@
             if args.shared:
                 create_dict[args.item]['shared'] = args.shared
         if "name" not in create_dict[args.item]:
-            print "You must provide a name in the descriptor file or with the --name option"
+            print("You must provide a name in the descriptor file or with the --name option")
             return
-        payload_req = yaml.safe_dump(create_dict, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True)
+        payload_req = yaml.safe_dump(create_dict, explicit_start=True, indent=4, default_flow_style=False, tags=False,
+                                     allow_unicode=True)
         logger.debug("openmano request: %s", payload_req)
-        URLrequest = "http://%s:%s/openmano/%s/vim/%s/%ss" %(mano_host, mano_port, tenant, datacenter, args.item)
+        URLrequest = "http://{}:{}/openmano/{}/vim/{}/{}s".format(mano_host, mano_port, tenant, datacenter, args.item)
         mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
         logger.debug("openmano response: %s", mano_response.text )
         if args.verbose==None:
@@ -1434,7 +1442,7 @@
 
 
 def _get_items(item, item_name_id=None, datacenter=None, tenant=None):
-    URLrequest = "http://%s:%s/openmano" %(mano_host, mano_port)
+    URLrequest = "http://{}:{}/openmano".format(mano_host, mano_port)
     if tenant:
         URLrequest += "/" + tenant
     if datacenter:
@@ -1469,7 +1477,7 @@
     if args.mac:
         payload_req['mac'] = args.mac
 
-    URLrequest = "http://%s:%s/openmano/%s/vim/%s/network/%s/attach" % (mano_host, mano_port, tenant, datacenter, network_uuid)
+    URLrequest = "http://{}:{}/openmano/{}/vim/{}/network/{}/attach".format(mano_host, mano_port, tenant, datacenter, network_uuid)
     logger.debug("openmano request: %s", payload_req)
     mano_response = requests.post(URLrequest, headers=headers_req, data=json.dumps(payload_req))
     logger.debug("openmano response: %s", mano_response.text)
@@ -1479,7 +1487,7 @@
 
 def vim_net_sdn_detach(args):
     if not args.all and not args.id:
-        print "--all or --id must be used"
+        print("--all or --id must be used")
         return 1
 
     # Verify the network exists in the vim
@@ -1494,15 +1502,15 @@
     network_uuid = content['network']['id']
 
     if not args.force:
-        r = raw_input("Confirm action' (y/N)? ")
+        r = input("Confirm action' (y/N)? ")
         if len(r) == 0 or r[0].lower() != "y":
             return 0
 
     if args.id:
-        URLrequest = "http://%s:%s/openmano/%s/vim/%s/network/%s/detach/%s" % (
+        URLrequest = "http://{}:{}/openmano/{}/vim/{}/network/{}/detach/{}".format(
             mano_host, mano_port, tenant, datacenter, network_uuid, args.id)
     else:
-        URLrequest = "http://%s:%s/openmano/%s/vim/%s/network/%s/detach" % (
+        URLrequest = "http://{}:{}/openmano/{}/vim/{}/network/{}/detach".format(
             mano_host, mano_port, tenant, datacenter, network_uuid)
     mano_response = requests.delete(URLrequest)
     logger.debug("openmano response: %s", mano_response.text)
@@ -1512,8 +1520,9 @@
 
 def datacenter_net_action(args):
     if args.action == "net-update":
-        print "This command is deprecated, use 'openmano datacenter-netmap-delete --all' and 'openmano datacenter-netmap-import' instead!!!"
-        print
+        print("This command is deprecated, use 'openmano datacenter-netmap-delete --all' and 'openmano"
+              " datacenter-netmap-import' instead!!!")
+        print()
         args.action = "netmap-delete"
         args.netmap = None
         args.all = True
@@ -1536,19 +1545,19 @@
     args.action = "netmap" + args.action[3:]
     args.vim_name=None
     args.vim_id=None
-    print "This command is deprecated, use 'openmano datacenter-%s' instead!!!" % args.action
-    print
+    print("This command is deprecated, use 'openmano datacenter-{}' instead!!!".format(args.action))
+    print()
     return datacenter_netmap_action(args)
 
 def datacenter_netmap_action(args):
     tenant = _get_tenant()
     datacenter = _get_datacenter(args.datacenter, tenant)
-    #print "datacenter_netmap_action",args
+    # print("datacenter_netmap_action",args)
     payload_req = None
     if args.verbose==None:
         args.verbose=0
     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
-    URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/netmaps" %(mano_host, mano_port, tenant, datacenter)
+    URLrequest = "http://{}:{}/openmano/{}/datacenters/{}/netmaps".format(mano_host, mano_port, tenant, datacenter)
 
     if args.action=="netmap-list":
         if args.netmap:
@@ -1558,18 +1567,18 @@
 
     elif args.action=="netmap-delete":
         if args.netmap and args.all:
-            print "you can not use a netmap name and the option --all at the same time"
+            print("you can not use a netmap name and the option --all at the same time")
             return 1
         if args.netmap:
-            force_text= "Delete default netmap '%s' from datacenter '%s' (y/N)? " % (args.netmap, datacenter)
+            force_text= "Delete default netmap '{}' from datacenter '{}' (y/N)? ".format(args.netmap, datacenter)
             URLrequest += "/" + args.netmap
         elif args.all:
-            force_text="Delete all default netmaps from datacenter '%s' (y/N)? " % (datacenter)
+            force_text="Delete all default netmaps from datacenter '{}' (y/N)? ".format(datacenter)
         else:
-            print "you must specify a netmap name or the option --all"
+            print("you must specify a netmap name or the option --all")
             return 1
         if not args.force:
-            r = raw_input(force_text)
+            r = input(force_text)
             if  len(r)>0  and r[0].lower()=="y":
                 pass
             else:
@@ -1577,7 +1586,7 @@
         mano_response = requests.delete(URLrequest, headers=headers_req)
     elif args.action=="netmap-import":
         if not args.force:
-            r = raw_input("Create all the available networks from datacenter '%s' as default netmaps (y/N)? " % (datacenter))
+            r = input("Create all the available networks from datacenter '{}' as default netmaps (y/N)? ".format(datacenter))
             if  len(r)>0  and r[0].lower()=="y":
                 pass
             else:
@@ -1602,9 +1611,9 @@
 
         if args.action=="netmap-edit" and not args.force:
             if len(payload["netmap"]) == 0:
-                print "You must supply some parameter to edit"
+                print("You must supply some parameter to edit")
                 return 1
-            r = raw_input("Edit default netmap '%s' from datacenter '%s' (y/N)? " % (args.netmap, datacenter))
+            r = input("Edit default netmap '{}' from datacenter '{}' (y/N)? ".format(args.netmap, datacenter))
             if  len(r)>0  and r[0].lower()=="y":
                 pass
             else:
@@ -1613,7 +1622,8 @@
             mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
         else: #netmap-create
             if "vim_name" not in payload["netmap"] and "vim_id" not in payload["netmap"]:
-                print "You must supply either --vim-id or --vim-name option; or include one of them in the file descriptor"
+                print("You must supply either --vim-id or --vim-name option; or include one of them in the file"
+                      " descriptor")
                 return 1
             mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
 
@@ -1624,15 +1634,15 @@
 def element_edit(args):
     element = _get_item_uuid(args.element, args.name)
     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
-    URLrequest = "http://%s:%s/openmano/%s/%s" %(mano_host, mano_port, args.element, element)
+    URLrequest = "http://{}:{}/openmano/{}/{}".format(mano_host, mano_port, args.element, element)
     payload=_load_file_or_yaml(args.file)
     if args.element[:-1] not in payload:
         payload = {args.element[:-1]: payload }
     payload_req = json.dumps(payload)
 
-    #print payload_req
+    # print(payload_req)
     if not args.force or (args.name==None and args.filer==None):
-        r = raw_input(" Edit " + args.element[:-1] + " " + args.name + " (y/N)? ")
+        r = input(" Edit " + args.element[:-1] + " " + args.name + " (y/N)? ")
         if  len(r)>0  and r[0].lower()=="y":
             pass
         else:
@@ -1651,7 +1661,7 @@
     tenant = _get_tenant()
     element = _get_item_uuid('datacenters', args.name, tenant)
     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
-    URLrequest = "http://%s:%s/openmano/datacenters/%s" % (mano_host, mano_port, element)
+    URLrequest = "http://{}:{}/openmano/datacenters/{}".format(mano_host, mano_port, element)
 
     has_arguments = False
     if args.file != None:
@@ -1678,9 +1688,9 @@
         payload = {'datacenter': payload}
     payload_req = json.dumps(payload)
 
-    # print payload_req
+    # print(payload_req)
     if not args.force or (args.name == None and args.filer == None):
-        r = raw_input(" Edit datacenter " + args.name + " (y/N)? ")
+        r = input(" Edit datacenter " + args.name + " (y/N)? ")
         if len(r) > 0 and r[0].lower() == "y":
             pass
         else:
@@ -1713,7 +1723,7 @@
 
     payload_req = json.dumps({"wim_account": wim_dict})
 
-    URLrequest = "http://%s:%s/openmano/%s/wims/%s" % (mano_host, mano_port, tenant, wim)
+    URLrequest = "http://{}:{}/openmano/{}/wims/{}".format(mano_host, mano_port, tenant, wim)
     logger.debug("openmano request: %s", payload_req)
     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
     logger.debug("openmano response: %s", mano_response.text)
@@ -1723,7 +1733,7 @@
         content = mano_response.json()
         if "already in use for  'name'" in content['error']['description'] and \
                 "to database wim_tenants table" in content['error']['description']:
-            print "Try to specify a different name with --wim-tenant-name"
+            print("Try to specify a different name with --wim-tenant-name")
     return result
 
 
@@ -1734,16 +1744,16 @@
         tenant = _get_tenant()
     wim = _get_wim(args.name, tenant)
     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
-    URLrequest = "http://%s:%s/openmano/%s/wims/%s" % (mano_host, mano_port, tenant, wim)
+    URLrequest = "http://{}:{}/openmano/{}/wims/{}".format(mano_host, mano_port, tenant, wim)
     mano_response = requests.delete(URLrequest, headers=headers_req)
     logger.debug("openmano response: %s", mano_response.text)
     content = mano_response.json()
-    # print json.dumps(content, indent=4)
+    # print(json.dumps(content, indent=4))
     result = 0 if mano_response.status_code == 200 else mano_response.status_code
     if mano_response.status_code == 200:
-        print content['result']
+        print(content['result'])
     else:
-        print content['error']['description']
+        print(content['error']['description'])
     return result
 
 
@@ -1764,9 +1774,9 @@
 
     payload_req = json.dumps({"wim_account": wim_dict})
 
-    # print payload_req
+    # print(payload_req)
 
-    URLrequest = "http://%s:%s/openmano/%s/wims/%s" % (mano_host, mano_port, tenant, wim)
+    URLrequest = "http://{}:{}/openmano/{}/wims/{}".format(mano_host, mano_port, tenant, wim)
     logger.debug("openmano request: %s", payload_req)
     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
     logger.debug("openmano response: %s", mano_response.text)
@@ -1776,7 +1786,7 @@
         content = mano_response.json()
         if "already in use for  'name'" in content['error']['description'] and \
                 "to database wim_tenants table" in content['error']['description']:
-            print "Try to specify a different name with --wim-tenant-name"
+            print("Try to specify a different name with --wim-tenant-name")
     return result
 
 def wim_create(args):
@@ -1791,7 +1801,7 @@
 
     payload_req = json.dumps({"wim": wim_dict})
 
-    URLrequest = "http://%s:%s/openmano/wims" % (mano_host, mano_port)
+    URLrequest = "http://{}:{}/openmano/wims".format(mano_host, mano_port)
     logger.debug("openmano request: %s", payload_req)
     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
     logger.debug("openmano response: %s", mano_response.text)
@@ -1802,7 +1812,7 @@
     tenant = _get_tenant()
     element = _get_item_uuid('wims', args.name, tenant)
     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
-    URLrequest = "http://%s:%s/openmano/wims/%s" % (mano_host, mano_port, element)
+    URLrequest = "http://{}:{}/openmano/wims/{}".format(mano_host, mano_port, element)
 
     has_arguments = False
     if args.file != None:
@@ -1818,9 +1828,9 @@
         payload = {'wim': payload}
     payload_req = json.dumps(payload)
 
-    # print payload_req
+    # print(payload_req)
     if not args.force or (args.name == None and args.filer == None):
-        r = raw_input(" Edit wim " + args.name + " (y/N)? ")
+        r = input(" Edit wim " + args.name + " (y/N)? ")
         if len(r) > 0 and r[0].lower() == "y":
             pass
         else:
@@ -1836,34 +1846,34 @@
 
 
 def wim_delete(args):
-    # print "wim-delete",args
+    # print("wim-delete",args)
     todelete = _get_item_uuid("wims", args.name, "any")
     if not args.force:
-        r = raw_input("Delete wim %s (y/N)? " % (args.name))
+        r = input("Delete wim {} (y/N)? ".format(args.name))
         if not (len(r) > 0 and r[0].lower() == "y"):
             return 0
-    URLrequest = "http://%s:%s/openmano/wims/%s" % (mano_host, mano_port, todelete)
+    URLrequest = "http://{}:{}/openmano/wims/{}".format(mano_host, mano_port, todelete)
     mano_response = requests.delete(URLrequest)
     logger.debug("openmano response: %s", mano_response.text)
     result = 0 if mano_response.status_code == 200 else mano_response.status_code
     content = mano_response.json()
-    # print json.dumps(content, indent=4)
+    # print(json.dumps(content, indent=4)
     if mano_response.status_code == 200:
-        print content['result']
+        print(content['result'])
     else:
-        print content['error']['description']
+        print(content['error']['description'])
     return result
 
 
 def wim_list(args):
-    # print "wim-list",args
+    # print("wim-list",args)
     tenant = 'any' if args.all else _get_tenant()
 
     if args.name:
         toshow = _get_item_uuid("wims", args.name, tenant)
-        URLrequest = "http://%s:%s/openmano/%s/wims/%s" % (mano_host, mano_port, tenant, toshow)
+        URLrequest = "http://{}:{}/openmano/{}/wims/{}".format(mano_host, mano_port, tenant, toshow)
     else:
-        URLrequest = "http://%s:%s/openmano/%s/wims" % (mano_host, mano_port, tenant)
+        URLrequest = "http://{}:{}/openmano/{}/wims".format(mano_host, mano_port, tenant)
     mano_response = requests.get(URLrequest)
     logger.debug("openmano response: %s", mano_response.text)
     if args.verbose == None:
@@ -1886,7 +1896,7 @@
     payload_req = json.dumps({"wim_port_mapping": wim_port_mapping})
 
     # read
-    URLrequest = "http://%s:%s/openmano/%s/wims/%s/port_mapping" % (mano_host, mano_port, tenant, wim)
+    URLrequest = "http://{}:{}/openmano/{}/wims/{}/port_mapping".format(mano_host, mano_port, tenant, wim)
     mano_response = requests.get(URLrequest)
     logger.debug("openmano response: %s", mano_response.text)
     port_mapping = mano_response.json()
@@ -1897,19 +1907,19 @@
     # TODO: check this if statement
     if len(port_mapping["wim_port_mapping"]) > 0:
         if not args.force:
-            r = raw_input("WIM %s already contains a port mapping. Overwrite? (y/N)? " % (wim))
+            r = input("WIM {} already contains a port mapping. Overwrite? (y/N)? ".format(wim))
             if not (len(r) > 0 and r[0].lower() == "y"):
                 return 0
 
         # clear
-        URLrequest = "http://%s:%s/openmano/%s/wims/%s/port_mapping" % (mano_host, mano_port, tenant, wim)
+        URLrequest = "http://{}:{}/openmano/{}/wims/{}/port_mapping".format(mano_host, mano_port, tenant, wim)
         mano_response = requests.delete(URLrequest)
         logger.debug("openmano response: %s", mano_response.text)
         if mano_response.status_code != 200:
             return _print_verbose(mano_response, args.verbose)
 
     # set
-    URLrequest = "http://%s:%s/openmano/%s/wims/%s/port_mapping" % (mano_host, mano_port, tenant, wim)
+    URLrequest = "http://{}:{}/openmano/{}/wims/{}/port_mapping".format(mano_host, mano_port, tenant, wim)
     logger.debug("openmano request: %s", payload_req)
     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
     logger.debug("openmano response: %s", mano_response.text)
@@ -1920,7 +1930,7 @@
     tenant = _get_tenant()
     wim = _get_wim(args.name, tenant)
 
-    URLrequest = "http://%s:%s/openmano/%s/wims/%s/port_mapping" % (mano_host, mano_port, tenant, wim)
+    URLrequest = "http://{}:{}/openmano/{}/wims/{}/port_mapping".format(mano_host, mano_port, tenant, wim)
     mano_response = requests.get(URLrequest)
     logger.debug("openmano response: %s", mano_response.text)
 
@@ -1932,38 +1942,37 @@
     wim = _get_wim(args.name, tenant)
 
     if not args.force:
-        r = raw_input("Clear WIM port mapping for wim %s (y/N)? " % (wim))
+        r = input("Clear WIM port mapping for wim {} (y/N)? ".format(wim))
         if not (len(r) > 0 and r[0].lower() == "y"):
             return 0
 
-    URLrequest = "http://%s:%s/openmano/%s/wims/%s/port_mapping" % (mano_host, mano_port, tenant, wim)
+    URLrequest = "http://{}:{}/openmano/{}/wims/{}/port_mapping".format(mano_host, mano_port, tenant, wim)
     mano_response = requests.delete(URLrequest)
     logger.debug("openmano response: %s", mano_response.text)
     content = mano_response.json()
-    # print json.dumps(content, indent=4)
+    # print(json.dumps(content, indent=4))
     result = 0 if mano_response.status_code == 200 else mano_response.status_code
     if mano_response.status_code == 200:
-        print content['result']
+        print(content['result'])
     else:
-        print content['error']['description']
+        print(content['error']['description'])
     return result
 
 
 def version(args):
     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
-    URLrequest = "http://%s:%s/openmano/version" % (mano_host, mano_port)
+    URLrequest = "http://{}:{}/openmano/version".format(mano_host, mano_port)
 
     mano_response = requests.get(URLrequest, headers=headers_req)
     logger.debug("openmano response: %s", mano_response.text)
-    print mano_response.text
+    print(mano_response.text)
 
 
-global mano_host
-global mano_port
-global mano_tenant
-
-if __name__=="__main__":
-
+def main():
+    global mano_host
+    global mano_port
+    global mano_tenant
+    global logger
     mano_tenant = os.getenv('OPENMANO_TENANT', None)
     mano_host = os.getenv('OPENMANO_HOST',"localhost")
     mano_port = os.getenv('OPENMANO_PORT',"9090")
@@ -2458,15 +2467,15 @@
 
         if item == "network" or item == "tenant":
             vim_item_create_parser = subparsers.add_parser(command_name + '-create', parents=[parent_parser], help="create a "+item+" at vim")
-            vim_item_create_parser.add_argument("file", nargs='?', help="descriptor of the %s. Must be a file or yaml/json text" % item).completer = FilesCompleter
-            vim_item_create_parser.add_argument("--name", action="store", help="name of the %s" % item  )
+            vim_item_create_parser.add_argument("file", nargs='?', help="descriptor of the {}. Must be a file or yaml/json text".format(item)).completer = FilesCompleter
+            vim_item_create_parser.add_argument("--name", action="store", help="name of the {}".format(item))
             vim_item_create_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
             if item=="network":
                 vim_item_create_parser.add_argument("--type", action="store", help="type of network, data, ptp, bridge")
                 vim_item_create_parser.add_argument("--shared", action="store_true", help="Private or shared")
                 vim_item_create_parser.add_argument("--bind-net", action="store", help="For openvim datacenter type, net to be bind to, for vlan type, use sufix ':<vlan_tag>'")
             else:
-                vim_item_create_parser.add_argument("--description", action="store", help="description of the %s" % item)
+                vim_item_create_parser.add_argument("--description", action="store", help="description of the {}".format(item))
             vim_item_create_parser.set_defaults(func=vim_action, item=item, action="create")
 
     argcomplete.autocomplete(main_parser)
@@ -2481,22 +2490,31 @@
         logging.basicConfig(format=streamformat, level= level)
         logger = logging.getLogger('mano')
         logger.setLevel(level)
+        # print("#TODO py3", args)
         result = args.func(args)
         if result == None:
             result = 0
         #for some reason it fails if call exit inside try instance. Need to call exit at the end !?
     except (requests.exceptions.ConnectionError):
-        print "Connection error: not possible to contact OPENMANO-SERVER (openmanod)"
+        print("Connection error: not possible to contact OPENMANO-SERVER (openmanod)")
         result = -2
     except (KeyboardInterrupt):
-        print 'Exiting openmano'
+        print('Exiting openmano')
         result = -3
     except (SystemExit, ArgumentParserError):
         result = -4
+    except (AttributeError):
+        print("Type '--help' for more information")
+        result = -4
     except OpenmanoCLIError as e:
-        print str(e)
+        # print("#TODO py3", e)
+        print(e)
         result = -5
 
-    #print result
+    # print(result)
     exit(result)
 
+
+if __name__ == '__main__':
+    main()
+
diff --git a/RO-client/requirements.txt b/RO-client/requirements.txt
new file mode 100644
index 0000000..fd9682c
--- /dev/null
+++ b/RO-client/requirements.txt
@@ -0,0 +1,17 @@
+##
+# 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.
+##
+
+argcomplete
+requests==2.*
+PyYAML
diff --git a/RO-client/setup.py b/RO-client/setup.py
new file mode 100644
index 0000000..d1748cd
--- /dev/null
+++ b/RO-client/setup.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+# Copyright 2018 Telefonica S.A.
+#
+# 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 os
+from setuptools import setup
+
+_name = "osm_roclient"
+# version is at first line of osm_roclient/html_public/version
+here = os.path.abspath(os.path.dirname(__file__))
+with open(os.path.join(here, 'README.rst')) as readme_file:
+    README = readme_file.read()
+
+setup(
+    name=_name,
+    description='OSM ro client',
+    long_description=README,
+    version_command=('git describe --match v* --tags --long --dirty', 'pep440-git-full'),
+    # version=VERSION,
+    # python_requires='>3.5.0',
+    author='ETSI OSM',
+    author_email='alfonso.tiernosepulveda@telefonica.com',
+    maintainer='Alfonso Tierno',
+    maintainer_email='alfonso.tiernosepulveda@telefonica.com',
+    url='https://osm.etsi.org/gitweb/?p=osm/LCM.git;a=summary',
+    license='Apache 2.0',
+
+    packages=[_name],
+    include_package_data=True,
+    # data_files=[('/etc/osm/', ['osm_roclient/lcm.cfg']),
+    #             ('/etc/systemd/system/', ['osm_roclient/osm-lcm.service']),
+    #             ],
+    install_requires=[
+        'PyYAML',
+        'requests==2.*',
+        'argcomplete',
+    ],
+    setup_requires=['setuptools-version-command'],
+    entry_points={
+        "console_scripts": [
+            "openmano=osm_roclient.roclient:main"
+        ]
+    },
+)
diff --git a/RO-client/stdeb.cfg b/RO-client/stdeb.cfg
new file mode 100644
index 0000000..844e87e
--- /dev/null
+++ b/RO-client/stdeb.cfg
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+[DEFAULT]
+X-Python3-Version : >= 3.5
+Depends3: python3-argcomplete, python3-requests, python3-yaml 
diff --git a/RO-client/tox.ini b/RO-client/tox.ini
new file mode 100644
index 0000000..a8e7c3a
--- /dev/null
+++ b/RO-client/tox.ini
@@ -0,0 +1,41 @@
+# Copyright 2018 Telefonica S.A.
+#
+# 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.
+
+[tox]
+envlist = py3
+toxworkdir={homedir}/.tox
+
+[testenv]
+basepython = python3
+install_command = python3 -m pip install -r requirements.txt -U {opts} {packages}
+deps = -r{toxinidir}/test-requirements.txt
+commands=python3 -m unittest discover -v
+
+[testenv:flake8]
+basepython = python3
+deps = flake8
+commands = flake8 osm_roclient --max-line-length 120 \
+    --exclude .svn,CVS,.gz,.git,__pycache__,.tox,local,temp --ignore W291,W293,E226,W504
+
+[testenv:unittest]
+basepython = python3
+commands = python3 -m unittest osm_roclient.tests
+
+[testenv:build]
+basepython = python3
+deps = stdeb
+       setuptools-version-command
+commands = python3 setup.py --command-packages=stdeb.command bdist_deb
+
diff --git a/RO/MANIFEST.in b/RO/MANIFEST.in
new file mode 100644
index 0000000..7251d31
--- /dev/null
+++ b/RO/MANIFEST.in
@@ -0,0 +1,21 @@
+##
+# 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.
+##
+
+#include MANIFEST.in
+#include requirements.txt
+include README.rst
+include requirements.txt
+include README.rst
+recursive-include osm_ro *
+
diff --git a/RO/Makefile b/RO/Makefile
new file mode 100644
index 0000000..b41748d
--- /dev/null
+++ b/RO/Makefile
@@ -0,0 +1,120 @@
+# Copyright 2018 Telefonica S.A.
+#
+# 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.
+
+.PHONY: all test clean
+
+SHELL := /bin/bash
+
+BRANCH ?= master
+
+all:  clean package
+
+clean:
+	rm -rf dist deb_dist osm_ro-*.tar.gz osm_ro.egg-info .eggs
+
+package:
+#	apt-get install -y python-stdeb
+	python3 setup.py --command-packages=stdeb.command sdist_dsc
+	cp debian/python3-osm-ro.postinst deb_dist/osm-ro*/debian/
+	cd deb_dist/osm-ro*/ && dpkg-buildpackage -rfakeroot -uc -us
+	# mkdir -p .build
+	# cp build/deb_dist/python-*.deb .build/
+
+clean_build:
+	rm -rf build
+	find osm_ro -name '*.pyc' -delete
+	find osm_ro -name '*.pyo' -delete
+
+prepare:
+#	ip install --user --upgrade setuptools
+	mkdir -p build/
+#	VER1=$(shell git describe | sed -e 's/^v//' |cut -d- -f1); \
+#	VER2=$(shell git describe | cut -d- -f2); \
+#	VER3=$(shell git describe | cut -d- -f3); \
+#	echo "$$VER1.dev$$VER2+$$VER3" > build/RO_VERSION
+	cp tox.ini build/
+	cp MANIFEST.in build/
+	cp requirements.txt build/
+	cp README.rst build/
+	cp setup.py build/
+	cp stdeb.cfg build/
+	cp -r osm_ro build/
+	cp openmano build/
+	cp openmanod build/
+	cp -r vnfs build/osm_ro
+	cp -r scenarios build/osm_ro
+	cp -r instance-scenarios build/osm_ro
+	cp -r scripts build/osm_ro
+	cp -r database_utils build/osm_ro
+	cp LICENSE build/osm_ro
+
+connectors: prepare
+	# python-novaclient is required for that
+	rm -f build/osm_ro/openmanolinkervimconn.py
+	cd build/osm_ro; for i in `ls vimconn_*.py |sed "s/\.py//"` ; do echo "import $$i" >> openmanolinkervimconn.py; done
+	python build/osm_ro/openmanolinkervimconn.py 2>&1
+	rm -f build/osm_ro/openmanolinkervimconn.py
+
+build: connectors prepare
+	python -m py_compile build/osm_ro/*.py
+#	cd build && tox -e flake8
+
+lib-openvim:
+	$(shell git clone https://osm.etsi.org/gerrit/osm/openvim)
+	LIB_BRANCH=$(shell git -C openvim branch -a|grep -oP 'remotes/origin/\K$(BRANCH)'); \
+	[ -z "$$LIB_BRANCH" ] && LIB_BRANCH='master'; \
+	echo "BRANCH: $(BRANCH)"; \
+	echo "LIB_OPENVIM_BRANCH: $$LIB_BRANCH"; \
+	git -C openvim checkout $$LIB_BRANCH
+	make -C openvim clean lite
+
+osm-im:
+	$(shell git clone https://osm.etsi.org/gerrit/osm/IM)
+	make -C IM clean all
+
+snap:
+	echo "Nothing to be done yet"
+
+install: lib-openvim osm-im
+	dpkg -i IM/deb_dist/python-osm-im*.deb
+	dpkg -i openvim/.build/python-lib-osm-openvim*.deb
+	dpkg -i .build/python-osm-ro*.deb
+	cd .. && \
+	OSMLIBOVIM_PATH=`python -c 'import lib_osm_openvim; print lib_osm_openvim.__path__[0]'` || FATAL "lib-osm-openvim was not properly installed" && \
+	OSMRO_PATH=`python -c 'import osm_ro; print osm_ro.__path__[0]'` || FATAL "osm-ro was not properly installed" && \
+	USER=root DEBIAN_FRONTEND=noninteractive $$OSMRO_PATH/database_utils/install-db-server.sh --updatedb || FATAL "osm-ro db installation failed" && \
+	USER=root DEBIAN_FRONTEND=noninteractive $$OSMLIBOVIM_PATH/database_utils/install-db-server.sh -u mano -p manopw -d mano_vim_db --updatedb || FATAL "lib-osm-openvim db installation failed"
+	service osm-ro restart
+
+develop: prepare
+#	pip install -r requirements.txt
+	cd build && ./setup.py develop
+
+test:
+	. ./test/basictest.sh -f --insert-bashrc --install-openvim --init-openvim
+	. ./test/basictest.sh -f reset add-openvim
+	./test/test_RO.py deploy -n mgmt -t osm -i cirros034 -d local-openvim --timeout=30 --failfast
+	./test/test_RO.py vim  -t osm  -d local-openvim --timeout=30 --failfast
+
+build-docker-from-source:
+	docker build -t osm/openmano -f docker/Dockerfile-local .
+
+run-docker:
+	docker-compose -f docker/openmano-compose.yml up
+
+stop-docker:
+	docker-compose -f docker/openmano-compose.yml down
+
+
diff --git a/RO/README.rst b/RO/README.rst
new file mode 100644
index 0000000..44a4fc4
--- /dev/null
+++ b/RO/README.rst
@@ -0,0 +1,22 @@
+ Copyright 2018 Telefonica S.A.
+ 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.
+
+===========
+osm-ro
+===========
+
+osm-ro is the Resource Orchestrator for OSM, dealing with resource operations
+against different VIMs such as Openstack, VMware's vCloud Director, openvim
+and AWS.
+
diff --git a/RO/debian/python3-osm-ro.postinst b/RO/debian/python3-osm-ro.postinst
new file mode 100755
index 0000000..02f356b
--- /dev/null
+++ b/RO/debian/python3-osm-ro.postinst
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+##
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: OSM_TECH@list.etsi.org
+##
+
+echo "POST INSTALL OSM-RO"
+# nothing to do
diff --git a/RO/osm_ro/__init__.py b/RO/osm_ro/__init__.py
new file mode 100644
index 0000000..7284a2b
--- /dev/null
+++ b/RO/osm_ro/__init__.py
@@ -0,0 +1,13 @@
+##
+# 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.
+##
diff --git a/osm_ro/console_proxy_thread.py b/RO/osm_ro/console_proxy_thread.py
similarity index 89%
rename from osm_ro/console_proxy_thread.py
rename to RO/osm_ro/console_proxy_thread.py
index 032c774..0c44899 100644
--- a/osm_ro/console_proxy_thread.py
+++ b/RO/osm_ro/console_proxy_thread.py
@@ -80,7 +80,7 @@
             raise ConsoleProxyException(type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0])) )
         
     def run(self):
-        while 1:
+        while True:
             try:
                 inputready, _, _ = select.select(self.input_list, [], [], self.check_finish)
             except select.error as e:
@@ -119,9 +119,9 @@
         try:
             forward = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
             forward.connect((self.console_host, self.console_port))
-            name = "%s:%d => (%s:%d => %s:%d) => %s:%d" %\
-                (clientsock.getpeername() + clientsock.getsockname()  + forward.getsockname() + forward.getpeername() )
-            self.logger.warn("new connection " + name)
+            name = "{}:{} => ({}:{} => {}:{}) => {}:{}".format(
+                *clientsock.getpeername(), *clientsock.getsockname(), *forward.getsockname(), *forward.getpeername() )
+            self.logger.warning("new connection " + name)
                 
             self.input_list.append(clientsock)
             self.input_list.append(forward)
@@ -142,22 +142,22 @@
         if sock not in self.channel:
             return  #can happen if there is data ready to received at both sides and the channel has been deleted. QUITE IMPROBABLE but just in case
         info = self.channel[sock]
-        #debug info
+        # debug info
         sockname = "client" if sock is info["clientsock"] else "server"
-        self.logger.warn("del connection %s %s at %s side", info["name"], str(cause), str(sockname) )
-        #close sockets
+        self.logger.warning("del connection %s %s at %s side", info["name"], str(cause), str(sockname))
+        # close sockets
         try:
             # close the connection with client
             info["clientsock"].close()  # equivalent to do self.s.close()
         except (socket.error, socket.herror, socket.gaierror, socket.timeout) as e:
-            self.logger.error("Exception on_close client socket %s: %s", type(e).__name__, str(e) )
+            self.logger.error("Exception on_close client socket %s: %s", type(e).__name__, str(e))
         try:
             # close the connection with remote server
             info["serversock"].close()
         except (socket.error, socket.herror, socket.gaierror, socket.timeout) as e:
             self.logger.error("Exception on_close server socket %s: %s", type(e).__name__, str(e) )
         
-        #remove objects from input_list
+        # remove objects from input_list
         self.input_list.remove(info["clientsock"])
         self.input_list.remove(info["serversock"])
         # delete both objects from channel dict
@@ -166,7 +166,7 @@
 
     def on_recv(self, sock):
         if sock not in self.channel:
-            return  #can happen if there is data ready to received at both sides and the channel has been deleted. QUITE IMPROBABLE but just in case
+            return  # can happen if there is data ready to received at both sides and the channel has been deleted. QUITE IMPROBABLE but just in case
         info = self.channel[sock]
         peersock = info["serversock"] if sock is info["clientsock"] else info["clientsock"]
         try:
@@ -174,12 +174,12 @@
             if len(data) == 0:
                 self.on_close(sock, "peer closed")
             else:
-                #print self.data
+                # print self.data
                 sock = peersock
                 peersock.send(data)
         except (socket.error, socket.herror, socket.gaierror, socket.timeout) as e:
-            #print self.name, ": Exception %s: %s" % (type(e).__name__, str(e) )
-            self.on_close(sock, "Exception %s: %s" % (type(e).__name__, str(e) ))
+            # print(self.name, ": Exception {}: {}".format(type(e).__name__, e))
+            self.on_close(sock, "Exception {}: {}".format(type(e).__name__, e))
 
         
 
diff --git a/database_utils/dump_db.sh b/RO/osm_ro/database_utils/dump_db.sh
similarity index 100%
rename from database_utils/dump_db.sh
rename to RO/osm_ro/database_utils/dump_db.sh
diff --git a/database_utils/init_mano_db.sh b/RO/osm_ro/database_utils/init_mano_db.sh
similarity index 100%
rename from database_utils/init_mano_db.sh
rename to RO/osm_ro/database_utils/init_mano_db.sh
diff --git a/database_utils/install-db-server.sh b/RO/osm_ro/database_utils/install-db-server.sh
similarity index 94%
rename from database_utils/install-db-server.sh
rename to RO/osm_ro/database_utils/install-db-server.sh
index 36b8003..8ef780c 100755
--- a/database_utils/install-db-server.sh
+++ b/RO/osm_ro/database_utils/install-db-server.sh
@@ -1,5 +1,22 @@
 #!/usr/bin/env bash
 
+##
+# Copyright Telefonica Investigacion y Desarrollo, S.A.U.
+# All Rights Reserved.
+#
+# 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.
+##
+
 DB_NAME='mano_db'
 DB_ADMIN_USER="root"
 DB_USER="mano"
diff --git a/database_utils/mano_db_structure.sql b/RO/osm_ro/database_utils/mano_db_structure.sql
similarity index 100%
rename from database_utils/mano_db_structure.sql
rename to RO/osm_ro/database_utils/mano_db_structure.sql
diff --git a/database_utils/migrate_mano_db.sh b/RO/osm_ro/database_utils/migrate_mano_db.sh
similarity index 95%
rename from database_utils/migrate_mano_db.sh
rename to RO/osm_ro/database_utils/migrate_mano_db.sh
index 096a21a..ab26ade 100755
--- a/database_utils/migrate_mano_db.sh
+++ b/RO/osm_ro/database_utils/migrate_mano_db.sh
@@ -36,7 +36,7 @@
 BACKUP_DIR=""
 BACKUP_FILE=""
 #TODO update it with the last database version
-LAST_DB_VERSION=39
+LAST_DB_VERSION=40
 
 # Detect paths
 MYSQL=$(which mysql)
@@ -197,6 +197,7 @@
 #[ $OPENMANO_VER_NUM -ge 6009 ] && DB_VERSION=37  #0.6.09 =>  37
 #[ $OPENMANO_VER_NUM -ge 6011 ] && DB_VERSION=38  #0.6.11 =>  38
 #[ $OPENMANO_VER_NUM -ge 6020 ] && DB_VERSION=39  #0.6.20 =>  39
+#[ $OPENMANO_VER_NUM -ge 6000004 ] && DB_VERSION=40  #6.0.4 =>  40
 #TODO ... put next versions here
 
 function upgrade_to_1(){
@@ -1461,6 +1462,56 @@
 
     sql "DELETE FROM schema_version WHERE version_int='39';"
 }
+function upgrade_to_40(){
+    echo "      Adding instance_wim_net_id, created_at, modified_at at 'instance_interfaces'"
+    sql "ALTER TABLE instance_interfaces ADD COLUMN instance_wim_net_id VARCHAR(36) NULL AFTER instance_net_id, " \
+        "ADD COLUMN model VARCHAR(12) NULL DEFAULT NULL AFTER type, " \
+        "ADD COLUMN created_at DOUBLE NULL DEFAULT NULL AFTER vlan, " \
+        "ADD COLUMN modified_at DOUBLE NULL DEFAULT NULL AFTER created_at;"
+    echo "      Adding sdn to 'instance_wim_nets'"
+    sql "ALTER TABLE instance_wim_nets ADD COLUMN sdn ENUM('true','false') NOT NULL DEFAULT 'false' AFTER created;"
+    echo "      Change from created to sdn at 'wim_accounts'"
+    sql "ALTER TABLE wim_accounts CHANGE COLUMN created sdn ENUM('true','false') NOT NULL DEFAULT 'false' AFTER wim_id;"
+    echo "      Remove unique_datacenter_port_mapping at 'wim_port_mappings'"
+    sql "ALTER TABLE wim_port_mappings DROP INDEX unique_datacenter_port_mapping;"
+    echo "      change 'wim_port_mappings' pop_x to device_x, adding switch_dpid, switch_port"
+    sql "ALTER TABLE wim_port_mappings ALTER pop_switch_dpid DROP DEFAULT, ALTER pop_switch_port DROP DEFAULT;"
+    sql "ALTER TABLE wim_port_mappings CHANGE COLUMN pop_switch_dpid device_id VARCHAR(64) NULL AFTER datacenter_id," \
+        " CHANGE COLUMN pop_switch_port device_interface_id VARCHAR(64) NULL AFTER device_id, " \
+        " CHANGE COLUMN wan_service_endpoint_id service_endpoint_id VARCHAR(256) NOT NULL AFTER device_interface_id, " \
+        " CHANGE COLUMN wan_service_mapping_info service_mapping_info TEXT NULL AFTER service_endpoint_id, " \
+        " ADD COLUMN switch_dpid VARCHAR(64) NULL AFTER service_endpoint_id," \
+        " ADD COLUMN switch_port VARCHAR(64) NULL AFTER switch_dpid;"
+    echo "      remove unique name to 'datacenters'"
+    sql "ALTER TABLE datacenters DROP INDEX name;"
+
+    sql "INSERT INTO schema_version (version_int, version, openmano_ver, comments, date) " \
+        "VALUES (40, '0.40', '6.0.4', 'Chagnes to SDN ', '2019-10-23');"
+}
+function downgrade_from_40(){
+    echo "      Removing instance_wim_net_id, created_at, modified_at from 'instance_interfaces'"
+    sql "ALTER TABLE instance_interfaces DROP COLUMN instance_wim_net_id, DROP COLUMN created_at, " \
+        "DROP COLUMN modified_at, DROP COLUMN model;"
+    echo "      Removing sdn from 'instance_wim_nets'"
+    sql "ALTER TABLE instance_wim_nets DROP COLUMN sdn;"
+    echo "      Change back from sdn to created at 'wim_accounts'"
+    sql "ALTER TABLE wim_accounts CHANGE COLUMN sdn created ENUM('true','false') NOT NULL DEFAULT 'false' AFTER wim_id;"
+    echo "      Restore back unique_datacenter_port_mapping at 'wim_port_mappings'"
+    echo "      change 'wim_port_mappings' device_x to pop_x, remove switch_dpid, switch_port"
+    sql "ALTER TABLE wim_port_mappings ALTER device_id DROP DEFAULT, ALTER device_interface_id DROP DEFAULT;"
+    sql "ALTER TABLE wim_port_mappings CHANGE COLUMN device_id pop_switch_dpid VARCHAR(64) NOT NULL AFTER " \
+        "datacenter_id,	CHANGE COLUMN device_interface_id pop_switch_port VARCHAR(64) NOT NULL AFTER pop_switch_dpid," \
+        " CHANGE COLUMN service_endpoint_id wan_service_endpoint_id VARCHAR(256) NOT NULL AFTER pop_switch_port, " \
+        " CHANGE COLUMN service_mapping_info wan_service_mapping_info TEXT NULL AFTER wan_service_endpoint_id, " \
+	      " DROP COLUMN switch_dpid, DROP COLUMN switch_port;"
+    sql "ALTER TABLE wim_port_mappings ADD UNIQUE INDEX unique_datacenter_port_mapping(datacenter_id, " \
+        "pop_switch_dpid, pop_switch_port);"
+    echo "      add unique name to 'datacenters'"
+    sql "ALTER TABLE datacenters ADD UNIQUE INDEX name (name);"
+    sql "DELETE FROM schema_version WHERE version_int='40';"
+}
+
+
 #TODO ... put functions here
 
 
diff --git a/database_utils/migrations/down/34_remove_wim_tables.sql b/RO/osm_ro/database_utils/migrations/down/34_remove_wim_tables.sql
similarity index 65%
rename from database_utils/migrations/down/34_remove_wim_tables.sql
rename to RO/osm_ro/database_utils/migrations/down/34_remove_wim_tables.sql
index 4400e39..7ab4bf7 100644
--- a/database_utils/migrations/down/34_remove_wim_tables.sql
+++ b/RO/osm_ro/database_utils/migrations/down/34_remove_wim_tables.sql
@@ -1,3 +1,16 @@
+/**
+* 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.
+**/
 --
 -- Tear down database structure required for integrating OSM with
 -- Wide Are Network Infrastructure Managers
diff --git a/RO/osm_ro/database_utils/migrations/down/35_remove_sfc_ingress_and_egress.sql b/RO/osm_ro/database_utils/migrations/down/35_remove_sfc_ingress_and_egress.sql
new file mode 100644
index 0000000..668eeb3
--- /dev/null
+++ b/RO/osm_ro/database_utils/migrations/down/35_remove_sfc_ingress_and_egress.sql
@@ -0,0 +1,29 @@
+/**
+* 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.
+**/
+--
+-- Removing ingress and egress ports for SFC purposes.
+-- Inserting only one port for ingress and egress.
+--
+
+ALTER TABLE sce_rsp_hops
+  DROP FOREIGN KEY FK_interfaces_rsp_hop_ingress,
+  CHANGE COLUMN ingress_interface_id interface_id VARCHAR(36) NOT NULL
+    AFTER if_order,
+  ADD CONSTRAINT FK_interfaces_rsp_hop
+    FOREIGN KEY (interface_id)
+    REFERENCES interfaces (uuid) ON UPDATE CASCADE ON DELETE CASCADE,
+  DROP FOREIGN KEY FK_interfaces_rsp_hop_egress,
+  DROP COLUMN egress_interface_id;
+
+DELETE FROM schema_version WHERE version_int='35';
diff --git a/database_utils/migrations/up/34_add_wim_tables.sql b/RO/osm_ro/database_utils/migrations/up/34_add_wim_tables.sql
similarity index 92%
rename from database_utils/migrations/up/34_add_wim_tables.sql
rename to RO/osm_ro/database_utils/migrations/up/34_add_wim_tables.sql
index 343f370..eb99b8b 100644
--- a/database_utils/migrations/up/34_add_wim_tables.sql
+++ b/RO/osm_ro/database_utils/migrations/up/34_add_wim_tables.sql
@@ -1,3 +1,16 @@
+/**
+* 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.
+**/
 --
 -- Setup database structure required for integrating OSM with
 -- Wide Are Network Infrastructure Managers
diff --git a/database_utils/migrations/up/35_add_sfc_ingress_and_egress.sql b/RO/osm_ro/database_utils/migrations/up/35_add_sfc_ingress_and_egress.sql
similarity index 65%
rename from database_utils/migrations/up/35_add_sfc_ingress_and_egress.sql
rename to RO/osm_ro/database_utils/migrations/up/35_add_sfc_ingress_and_egress.sql
index b528c6d..fea4cef 100644
--- a/database_utils/migrations/up/35_add_sfc_ingress_and_egress.sql
+++ b/RO/osm_ro/database_utils/migrations/up/35_add_sfc_ingress_and_egress.sql
@@ -1,3 +1,16 @@
+/**
+* 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.
+**/
 --
 -- Adding different ingress and egress ports for SFC.
 --
diff --git a/osm_ro/db_base.py b/RO/osm_ro/db_base.py
similarity index 97%
rename from osm_ro/db_base.py
rename to RO/osm_ro/db_base.py
index e6e1134..9c13133 100644
--- a/osm_ro/db_base.py
+++ b/RO/osm_ro/db_base.py
@@ -29,7 +29,7 @@
 
 import MySQLdb as mdb
 import uuid as myUuid
-import  utils as af
+from osm_ro import utils as af
 import json
 #import yaml
 import time
@@ -164,12 +164,14 @@
                     pos = value.find("bps")
                     if pos>0:
                         if value[pos-1]=="G": data["bandwidth"] =  int(data["bandwidth"][:pos-1]) * 1000
-                        elif value[pos-1]=="k": data["bandwidth"]= int(data["bandwidth"][:pos-1]) / 1000
+                        elif value[pos-1]=="k": data["bandwidth"]= int(data["bandwidth"][:pos-1]) // 1000
                         else: data["bandwidth"]= int(data["bandwidth"][:pos-1])
                 else:
                     value = int(data["bandwidth"])
-                    if value % 1000 == 0: data["bandwidth"]=str(value/1000) + " Gbps"
-                    else: data["bandwidth"]=str(value) + " Mbps"
+                    if value % 1000 == 0:
+                        data["bandwidth"] = str(value // 1000) + " Gbps"
+                    else:
+                        data["bandwidth"] = str(value) + " Mbps"
             except:
                 if logger:
                     logger.error("convert_bandwidth exception for type '%s' data '%s'", type(data["bandwidth"]), data["bandwidth"])
@@ -248,8 +250,6 @@
         return self.con.escape(value)
 
     def escape_string(self, value):
-        if isinstance(value, unicode):
-            value = value.encode("utf8")
         return self.con.escape_string(value)
 
     @retry
@@ -280,7 +280,7 @@
             return
         except AttributeError as e: #self.con not defined
             if e[0][-5:] == "'con'":
-                self.logger.warn("while disconnecting from DB: Error %d: %s",e.args[0], e.args[1])
+                self.logger.warning("while disconnecting from DB: Error %d: %s",e.args[0], e.args[1])
                 return
             else:
                 raise
@@ -364,8 +364,7 @@
         '''  # the **_ ignores extra kwargs
         table_info = ' (table `{}`)'.format(table) if table else ''
         if cmd:
-            self.logger.debug("Exception '%s' with command '%s'%s",
-                              e, cmd, table_info)
+            self.logger.debug("Exception '%s' with command '%s'%s", e, cmd, table_info)
 
         if isinstance(e,AttributeError ):
             self.logger.debug(str(e), exc_info=True)
@@ -376,7 +375,7 @@
             self.reconnect()
 
             if tries > 1:
-                self.logger.warn("DB Exception '%s'. Retry", str(e))
+                self.logger.warning("DB Exception '%s'. Retry", str(e))
                 return
             else:
                 raise db_base_Exception("Database connection timeout Try Again", httperrors.Request_Timeout)
@@ -422,7 +421,7 @@
         """
         if data is None:
             return 'Null'
-        elif isinstance(data[1], (str, unicode)):
+        elif isinstance(data[1], str):
             return json.dumps(data)
         else:
             return json.dumps(str(data))
@@ -438,7 +437,7 @@
         """
         if data[1] is None:
             return str(data[0]) + "=Null"
-        elif isinstance(data[1], (str, unicode)):
+        elif isinstance(data[1], str):
             return str(data[0]) + '=' + json.dumps(data[1])
         elif isinstance(data[1], dict):
             if "INCREMENT" in data[1]:
@@ -483,12 +482,12 @@
                     for v2 in v:
                         if v2 is None:
                             cmd2.append(k.replace("=", " is").replace("<>", " is not") + " Null")
-                        elif isinstance(v2, (str, unicode)):
+                        elif isinstance(v2, str):
                             cmd2.append(k + json.dumps(v2))
                         else:
                             cmd2.append(k + json.dumps(str(v2)))
                     cmd.append("(" + " OR ".join(cmd2) + ")")
-                elif isinstance(v, (str, unicode)):
+                elif isinstance(v, str):
                     cmd.append(k + json.dumps(v))
                 else:
                     cmd.append(k + json.dumps(str(v)))
@@ -524,7 +523,7 @@
         :return: the number of updated rows, raises exception upon error
         """
         # gettting uuid
-        values = ",".join(map(self.__tuple2db_format_set, UPDATE.iteritems() ))
+        values = ",".join(map(self.__tuple2db_format_set, UPDATE.items() ))
         if modified_time:
             values += ",modified_at={:f}".format(modified_time)
         cmd= "UPDATE " + table + " SET " + values + " WHERE " + self.__create_where(WHERE)
@@ -589,7 +588,7 @@
             self.cur.execute(cmd)
         #insertion
         cmd= "INSERT INTO " + table +" SET " + \
-            ",".join(map(self.__tuple2db_format_set, INSERT.iteritems() ))
+            ",".join(map(self.__tuple2db_format_set, INSERT.items() ))
         if created_time:
             cmd += ",created_at={time:.9f},modified_at={time:.9f}".format(time=created_time)
         if confidential_data:
@@ -810,7 +809,7 @@
         self.cur.execute("SELECT * FROM " + table + " WHERE "+ where_text)
         rows = self.cur.fetchall()
         if self.cur.rowcount==0:
-            return 0, "Name %s not found in table %s" %(name, table)
+            return 0, "Name {} not found in table {}".format(name, table)
         elif self.cur.rowcount>1:
-            return self.cur.rowcount, "More than one VNF with name %s found in table %s" %(name, table)
+            return self.cur.rowcount, "More than one VNF with name {} found in table {}".format(name, table)
         return self.cur.rowcount, rows[0]["uuid"]
diff --git a/RO/osm_ro/http_tools/__init__.py b/RO/osm_ro/http_tools/__init__.py
new file mode 100644
index 0000000..7284a2b
--- /dev/null
+++ b/RO/osm_ro/http_tools/__init__.py
@@ -0,0 +1,13 @@
+##
+# 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.
+##
diff --git a/osm_ro/http_tools/errors.py b/RO/osm_ro/http_tools/errors.py
similarity index 78%
rename from osm_ro/http_tools/errors.py
rename to RO/osm_ro/http_tools/errors.py
index 552e85b..2a3f027 100644
--- a/osm_ro/http_tools/errors.py
+++ b/RO/osm_ro/http_tools/errors.py
@@ -1,4 +1,18 @@
 # -*- coding: utf-8 -*-
+##
+# 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 logging
 from functools import wraps
 
diff --git a/osm_ro/http_tools/handler.py b/RO/osm_ro/http_tools/handler.py
similarity index 100%
rename from osm_ro/http_tools/handler.py
rename to RO/osm_ro/http_tools/handler.py
diff --git a/osm_ro/http_tools/request_processing.py b/RO/osm_ro/http_tools/request_processing.py
similarity index 88%
rename from osm_ro/http_tools/request_processing.py
rename to RO/osm_ro/http_tools/request_processing.py
index f2dabc8..7285142 100644
--- a/osm_ro/http_tools/request_processing.py
+++ b/RO/osm_ro/http_tools/request_processing.py
@@ -1,4 +1,17 @@
 # -*- coding: utf-8 -*-
+##
+# 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.
+##
 
 #
 # Util functions previously in `httpserver`
@@ -15,6 +28,7 @@
 from jsonschema import validate as js_v
 
 from . import errors as httperrors
+from io import TextIOWrapper
 
 logger = logging.getLogger('openmano.http')
 
@@ -64,13 +78,13 @@
     '''Return string of dictionary data according to requested json, yaml, xml.
     By default json
     '''
-    logger.debug("OUT: " + yaml.safe_dump(data, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True) )
+    logger.debug("OUT: " + yaml.safe_dump(data, explicit_start=True, indent=4, default_flow_style=False, tags=False, allow_unicode=True) )
     accept = bottle.request.headers.get('Accept')
     if accept and 'application/yaml' in accept:
         bottle.response.content_type='application/yaml'
         return yaml.safe_dump(
                 data, explicit_start=True, indent=4, default_flow_style=False,
-                tags=False, encoding='utf-8', allow_unicode=True) #, canonical=True, default_style='"'
+                tags=False, allow_unicode=True) #, canonical=True, default_style='"'
     else: #by default json
         bottle.response.content_type='application/json'
         #return data #json no style
@@ -102,11 +116,11 @@
         if 'application/json' in format_type:
             error_text = "Invalid json format "
             #Use the json decoder instead of bottle decoder because it informs about the location of error formats with a ValueError exception
-            client_data = json.load(bottle.request.body)
+            client_data = json.load(TextIOWrapper(bottle.request.body, encoding="utf-8"))  # TODO py3
             #client_data = bottle.request.json()
         elif 'application/yaml' in format_type:
             error_text = "Invalid yaml format "
-            client_data = yaml.load(bottle.request.body)
+            client_data = yaml.load(bottle.request.body, Loader=yaml.Loader)
         elif 'application/xml' in format_type:
             bottle.abort(501, "Content-Type: application/xml not supported yet.")
         else:
@@ -118,10 +132,10 @@
         #    return
         if confidential_data:
             logger.debug('IN: %s', remove_clear_passwd (yaml.safe_dump(client_data, explicit_start=True, indent=4, default_flow_style=False,
-                                              tags=False, encoding='utf-8', allow_unicode=True)))
+                                              tags=False, allow_unicode=True)))
         else:
             logger.debug('IN: %s', yaml.safe_dump(client_data, explicit_start=True, indent=4, default_flow_style=False,
-                                              tags=False, encoding='utf-8', allow_unicode=True) )
+                                              tags=False, allow_unicode=True) )
         # look for the client provider version
         error_text = "Invalid content "
         if not default_schema and not version_fields:
diff --git a/RO/osm_ro/http_tools/tests/__init__.py b/RO/osm_ro/http_tools/tests/__init__.py
new file mode 100644
index 0000000..7284a2b
--- /dev/null
+++ b/RO/osm_ro/http_tools/tests/__init__.py
@@ -0,0 +1,13 @@
+##
+# 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.
+##
diff --git a/osm_ro/http_tools/tests/test_errors.py b/RO/osm_ro/http_tools/tests/test_errors.py
similarity index 82%
rename from osm_ro/http_tools/tests/test_errors.py
rename to RO/osm_ro/http_tools/tests/test_errors.py
index a968e76..e2b1d43 100644
--- a/osm_ro/http_tools/tests/test_errors.py
+++ b/RO/osm_ro/http_tools/tests/test_errors.py
@@ -1,4 +1,18 @@
 # -*- coding: utf-8 -*-
+##
+# 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 unittest
 
 import bottle
diff --git a/osm_ro/http_tools/tests/test_handler.py b/RO/osm_ro/http_tools/tests/test_handler.py
similarity index 85%
rename from osm_ro/http_tools/tests/test_handler.py
rename to RO/osm_ro/http_tools/tests/test_handler.py
index af32545..e015758 100644
--- a/osm_ro/http_tools/tests/test_handler.py
+++ b/RO/osm_ro/http_tools/tests/test_handler.py
@@ -1,4 +1,18 @@
 # -*- coding: utf-8 -*-
+##
+# 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 unittest
 
 from mock import MagicMock, patch
diff --git a/osm_ro/http_tools/tox.ini b/RO/osm_ro/http_tools/tox.ini
similarity index 60%
rename from osm_ro/http_tools/tox.ini
rename to RO/osm_ro/http_tools/tox.ini
index 43055c2..93e2f15 100644
--- a/osm_ro/http_tools/tox.ini
+++ b/RO/osm_ro/http_tools/tox.ini
@@ -1,3 +1,17 @@
+##
+# 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.
+##
+
 # This tox file allows the devs to run unit tests only for this subpackage.
 # In order to do so, cd into the directory and run `tox`
 
diff --git a/osm_ro/httpserver.py b/RO/osm_ro/httpserver.py
similarity index 98%
rename from osm_ro/httpserver.py
rename to RO/osm_ro/httpserver.py
index 613fb08..d86271c 100644
--- a/osm_ro/httpserver.py
+++ b/RO/osm_ro/httpserver.py
@@ -34,7 +34,7 @@
 import threading
 import logging
 
-from openmano_schemas import vnfd_schema_v01, vnfd_schema_v02, \
+from osm_ro.openmano_schemas import vnfd_schema_v01, vnfd_schema_v02, \
                             nsd_schema_v01, nsd_schema_v02, nsd_schema_v03, scenario_edit_schema, \
                             scenario_action_schema, instance_scenario_action_schema, instance_scenario_create_schema_v01, \
                             tenant_schema, tenant_edit_schema,\
@@ -50,9 +50,9 @@
 )
 from .wim.http_handler import WimHandler
 
-import nfvo
-import utils
-from db_base import db_base_Exception
+from . import nfvo
+from . import utils
+from .db_base import db_base_Exception
 from functools import wraps
 
 global mydb
@@ -314,7 +314,7 @@
                     vim_account["passwd"] = "******"
                 if vim_account['config'] != None:
                     try:
-                        config_dict = yaml.load(vim_account['config'])
+                        config_dict = yaml.load(vim_account['config'], Loader=yaml.Loader)
                         vim_account['config'] = config_dict
                         if vim_account['config'].get('admin_password'):
                             vim_account['config']['admin_password'] = "******"
@@ -383,7 +383,7 @@
                     vim_tenant["passwd"] = "******"
                 if vim_tenant['config'] != None:
                     try:
-                        config_dict = yaml.load(vim_tenant['config'])
+                        config_dict = yaml.load(vim_tenant['config'], Loader=yaml.Loader)
                         vim_tenant['config'] = config_dict
                         if vim_tenant['config'].get('admin_password'):
                             vim_tenant['config']['admin_password'] = "******"
@@ -396,7 +396,7 @@
 
         if datacenter['config'] != None:
             try:
-                config_dict = yaml.load(datacenter['config'])
+                config_dict = yaml.load(datacenter['config'], Loader=yaml.Loader)
                 datacenter['config'] = config_dict
                 if datacenter['config'].get('admin_password'):
                     datacenter['config']['admin_password'] = "******"
@@ -636,7 +636,7 @@
         if netmap_id and len(netmaps)==1:
             data={'netmap' : netmaps[0]}
         elif netmap_id and len(netmaps)==0:
-            bottle.abort(httperrors.Not_Found, "No netmap found with " + " and ".join(map(lambda x: str(x[0])+": "+str(x[1]), where_.iteritems())) )
+            bottle.abort(httperrors.Not_Found, "No netmap found with " + " and ".join(map(lambda x: str(x[0])+": "+str(x[1]), where_.items())) )
             return
         else:
             data={'netmaps' : netmaps}
@@ -668,11 +668,11 @@
         #change_keys_http2db(content, http2db_tenant, reverse=True)
         deleted = mydb.delete_row(FROM='datacenter_nets', WHERE= where_)
         if deleted == 0 and netmap_id:
-            bottle.abort(httperrors.Not_Found, "No netmap found with " + " and ".join(map(lambda x: str(x[0])+": "+str(x[1]), where_.iteritems())) )
+            bottle.abort(httperrors.Not_Found, "No netmap found with " + " and ".join(map(lambda x: str(x[0])+": "+str(x[1]), where_.items())) )
         if netmap_id:
-            return format_out({"result": "netmap %s deleted" % netmap_id})
+            return format_out({"result": "netmap {} deleted".format(netmap_id)})
         else:
-            return format_out({"result": "%d netmap deleted" % deleted})
+            return format_out({"result": "{} netmap deleted".format(deleted)})
     except bottle.HTTPError:
         raise
     except (nfvo.NfvoException, db_base_Exception) as e:
@@ -1081,7 +1081,7 @@
             result, data = nfvo.get_hosts_info(mydb, tenant_id) #, datacenter)
 
         if result < 0:
-            #print "http_get_hosts error %d %s" % (-result, data)
+            #print("http_get_hosts error {} {}".format((-result, data))
             bottle.abort(-result, data)
         else:
             utils.convert_float_timestamp2str(data)
diff --git a/osm_ro/nfvo.py b/RO/osm_ro/nfvo.py
similarity index 94%
rename from osm_ro/nfvo.py
rename to RO/osm_ro/nfvo.py
index 8637245..b33bda3 100644
--- a/osm_ro/nfvo.py
+++ b/RO/osm_ro/nfvo.py
@@ -30,33 +30,41 @@
 # import imp
 import json
 import yaml
-import utils
-from utils import deprecated
-import vim_thread
-import console_proxy_thread as cli
-import vimconn
+from osm_ro import utils
+from osm_ro.utils import deprecated
+from osm_ro.vim_thread import vim_thread
+import osm_ro.console_proxy_thread as cli
+from osm_ro import vimconn
 import logging
 import collections
 import math
 from uuid import uuid4
-from db_base import db_base_Exception
+from osm_ro.db_base import db_base_Exception
 
-import nfvo_db
+from osm_ro import nfvo_db
 from threading import Lock
 import time as t
-from lib_osm_openvim import ovim as ovim_module
-from lib_osm_openvim.ovim import ovimException
+# TODO py3 BEGIN
+from osm_ro.sdn import Sdn, SdnException as ovimException
+# from lib_osm_openvim.ovim import ovimException
+# from unittest.mock  import MagicMock
+# class ovimException(Exception):
+#    pass
+# TODO py3 END
+
 from Crypto.PublicKey import RSA
 
 import osm_im.vnfd as vnfd_catalog
 import osm_im.nsd as nsd_catalog
 from pyangbind.lib.serialise import pybindJSONDecoder
 from copy import deepcopy
+from pkg_resources import iter_entry_points
 
 
 # WIM
-import wim.wimconn as wimconn
-import wim.wim_thread as wim_thread
+from .wim import sdnconn
+from .wim.wimconn_fake import FakeConnector
+from .wim.failing_connector import FailingConnector
 from .http_tools import errors as httperrors
 from .wim.engine import WimEngine
 from .wim.persistence import WimPersistence
@@ -65,11 +73,10 @@
 #
 
 global global_config
-global vimconn_imported
 # WIM
 global wim_engine
 wim_engine  = None
-global wimconn_imported
+global sdnconn_imported
 #
 global logger
 global default_volume_size
@@ -78,11 +85,11 @@
 ovim = None
 global_config = None
 
-vimconn_imported = {}   # dictionary with VIM type as key, loaded module as value
+plugins = {}   # dictionary with VIM type as key, loaded module as value
 vim_threads = {"running":{}, "deleting": {}, "names": []}      # threads running for attached-VIMs
 vim_persistent_info = {}
 # WIM
-wimconn_imported = {}   # dictionary with WIM type as key, loaded module as value
+sdnconn_imported = {}   # dictionary with WIM type as key, loaded module as value
 wim_threads = {"running":{}, "deleting": {}, "names": []}      # threads running for attached-WIMs
 wim_persistent_info = {}
 #
@@ -97,6 +104,23 @@
 class NfvoException(httperrors.HttpMappedError):
     """Common Class for NFVO errors"""
 
+def _load_plugin(name, type="vim"):
+    # type can be vim or sdn
+    global plugins
+    try:
+        for v in iter_entry_points('osm_ro{}.plugins'.format(type), name):
+            plugins[name] = v.load()
+    except Exception as e:
+        logger.critical("Cannot load osm_{}: {}".format(name, e))
+        if name:
+            plugins[name] = FailingConnector("Cannot load osm_{}: {}".format(name, e))
+    if name and name not in plugins:
+        error_text = "Cannot load a module for {t} type '{n}'. The plugin 'osm_{n}' has not been" \
+                     " registered".format(t=type, n=name)
+        logger.critical(error_text)
+        plugins[name] = FailingConnector(error_text)
+        # raise NfvoException("Cannot load a module for {t} type '{n}'. The plugin 'osm_{n}' has not been registered".
+        #                     format(t=type, n=name), httperrors.Bad_Request)
 
 def get_task_id():
     global last_task_id
@@ -151,37 +175,21 @@
 
 
 def start_service(mydb, persistence=None, wim=None):
-    global db, global_config
+    global db, global_config, plugins, ovim
     db = nfvo_db.nfvo_db(lock=db_lock)
     mydb.lock = db_lock
     db.connect(global_config['db_host'], global_config['db_user'], global_config['db_passwd'], global_config['db_name'])
-    global ovim
 
     persistence = persistence or  WimPersistence(db)
 
-    # Initialize openvim for SDN control
-    # TODO: Avoid static configuration by adding new parameters to openmanod.cfg
-    # TODO: review ovim.py to delete not needed configuration
-    ovim_configuration = {
-        'logger_name': 'openmano.ovim',
-        'network_vlan_range_start': 1000,
-        'network_vlan_range_end': 4096,
-        'db_name': global_config["db_ovim_name"],
-        'db_host': global_config["db_ovim_host"],
-        'db_user': global_config["db_ovim_user"],
-        'db_passwd': global_config["db_ovim_passwd"],
-        'bridge_ifaces': {},
-        'mode': 'normal',
-        'network_type': 'bridge',
-        #TODO: log_level_of should not be needed. To be modified in ovim
-        'log_level_of': 'DEBUG'
-    }
     try:
+        if "rosdn_fake" not in plugins:
+            plugins["rosdn_fake"] = FakeConnector
         # starts ovim library
-        ovim = ovim_module.ovim(ovim_configuration)
+        ovim = Sdn(db, plugins)
 
         global wim_engine
-        wim_engine = wim or WimEngine(persistence)
+        wim_engine = wim or WimEngine(persistence, plugins)
         wim_engine.ovim = ovim
 
         ovim.start_service()
@@ -201,30 +209,19 @@
             extra={'datacenter_tenant_id': vim.get('datacenter_tenant_id'),
                    'datacenter_id': vim.get('datacenter_id')}
             if vim["config"]:
-                extra.update(yaml.load(vim["config"]))
+                extra.update(yaml.load(vim["config"], Loader=yaml.Loader))
             if vim.get('dt_config'):
-                extra.update(yaml.load(vim["dt_config"]))
-            if vim["type"] not in vimconn_imported:
-                module_info=None
-                try:
-                    module = "vimconn_" + vim["type"]
-                    pkg = __import__("osm_ro." + module)
-                    vim_conn = getattr(pkg, module)
-                    # module_info = imp.find_module(module, [__file__[:__file__.rfind("/")]])
-                    # vim_conn = imp.load_module(vim["type"], *module_info)
-                    vimconn_imported[vim["type"]] = vim_conn
-                except (IOError, ImportError) as e:
-                    # if module_info and module_info[0]:
-                    #    file.close(module_info[0])
-                    raise NfvoException("Unknown vim type '{}'. Cannot open file '{}.py'; {}: {}".format(
-                        vim["type"], module, type(e).__name__, str(e)), httperrors.Bad_Request)
+                extra.update(yaml.load(vim["dt_config"], Loader=yaml.Loader))
+            plugin_name = "rovim_" + vim["type"]
+            if plugin_name not in plugins:
+                _load_plugin(plugin_name, type="vim")
 
             thread_id = vim['datacenter_tenant_id']
             vim_persistent_info[thread_id] = {}
             try:
                 #if not tenant:
                 #    return -httperrors.Bad_Request, "You must provide a valid tenant name or uuid for VIM  %s" % ( vim["type"])
-                myvim = vimconn_imported[ vim["type"] ].vimconnector(
+                myvim = plugins[plugin_name].vimconnector(
                     uuid=vim['datacenter_id'], name=vim['datacenter_name'],
                     tenant_id=vim['vim_tenant_id'], tenant_name=vim['vim_tenant_name'],
                     url=vim['vim_url'], url_admin=vim['vim_url_admin'],
@@ -236,19 +233,33 @@
                 logger.error("Cannot launch thread for VIM {} '{}': {}".format(vim['datacenter_name'],
                                                                                vim['datacenter_id'], e))
             except Exception as e:
-                raise NfvoException("Error at VIM  {}; {}: {}".format(vim["type"], type(e).__name__, e),
-                                    httperrors.Internal_Server_Error)
+                logger.critical("Cannot launch thread for VIM {} '{}': {}".format(vim['datacenter_name'],
+                                                                                  vim['datacenter_id'], e))
+                # raise NfvoException("Error at VIM  {}; {}: {}".format(vim["type"], type(e).__name__, e),
+                #                     httperrors.Internal_Server_Error)
             thread_name = get_non_used_vim_name(vim['datacenter_name'], vim['datacenter_id'], vim['vim_tenant_name'],
                                                 vim['vim_tenant_id'])
-            new_thread = vim_thread.vim_thread(task_lock, thread_name, vim['datacenter_name'],
-                                               vim['datacenter_tenant_id'], db=db, db_lock=db_lock, ovim=ovim)
+            new_thread = vim_thread(task_lock, plugins, thread_name, None,
+                                    vim['datacenter_tenant_id'], db=db)
             new_thread.start()
             vim_threads["running"][thread_id] = new_thread
+        wims = mydb.get_rows(FROM="wim_accounts join wims on wim_accounts.wim_id=wims.uuid",
+                             WHERE={"sdn": "true"},
+                             SELECT=("wim_accounts.uuid as uuid", "type", "wim_accounts.name as name"))
+        for wim in wims:
+            plugin_name = "rosdn_" + wim["type"]
+            if plugin_name not in plugins:
+                _load_plugin(plugin_name, type="sdn")
 
+            thread_id = wim['uuid']
+            thread_name = get_non_used_vim_name(wim['name'], wim['uuid'], wim['uuid'], None)
+            new_thread = vim_thread(task_lock, plugins, thread_name, wim['uuid'], None, db=db)
+            new_thread.start()
+            vim_threads["running"][thread_id] = new_thread
         wim_engine.start_threads()
     except db_base_Exception as e:
         raise NfvoException(str(e) + " at nfvo.get_vim", e.http_code)
-    except ovim_module.ovimException as e:
+    except ovimException as e:
         message = str(e)
         if message[:22] == "DATABASE wrong version":
             message = "DATABASE wrong version of lib_osm_openvim {msg} -d{dbname} -u{dbuser} -p{dbpass} {ver}' "\
@@ -349,7 +360,7 @@
         if vm["image_id"] and vm["image_id"] not in image_list:
             image_list.append(vm["image_id"])
         if vm["image_list"]:
-            vm_image_list = yaml.load(vm["image_list"])
+            vm_image_list = yaml.load(vm["image_list"], Loader=yaml.Loader)
             for image_dict in vm_image_list:
                 if image_dict["image_id"] not in image_list:
                     image_list.append(image_dict["image_id"])
@@ -363,6 +374,7 @@
             'nfvo_tenant_id','datacenter_id','vim_tenant_id','vim_url','vim_url_admin','datacenter_name','type','user','passwd'
         raise exception upon error
     '''
+    global plugins
     WHERE_dict={}
     if nfvo_tenant     is not None:  WHERE_dict['nfvo_tenant_id'] = nfvo_tenant
     if datacenter_id   is not None:  WHERE_dict['d.uuid']  = datacenter_id
@@ -386,28 +398,19 @@
                    'datacenter_id': vim.get('datacenter_id'),
                    '_vim_type_internal': vim.get('type')}
             if vim["config"]:
-                extra.update(yaml.load(vim["config"]))
+                extra.update(yaml.load(vim["config"], Loader=yaml.Loader))
             if vim.get('dt_config'):
-                extra.update(yaml.load(vim["dt_config"]))
-            if vim["type"] not in vimconn_imported:
-                module_info=None
+                extra.update(yaml.load(vim["dt_config"], Loader=yaml.Loader))
+            plugin_name = "rovim_" + vim["type"]
+            if plugin_name not in plugins:
                 try:
-                    module = "vimconn_" + vim["type"]
-                    pkg = __import__("osm_ro." + module)
-                    vim_conn = getattr(pkg, module)
-                    # module_info = imp.find_module(module, [__file__[:__file__.rfind("/")]])
-                    # vim_conn = imp.load_module(vim["type"], *module_info)
-                    vimconn_imported[vim["type"]] = vim_conn
-                except (IOError, ImportError) as e:
-                    # if module_info and module_info[0]:
-                    #     file.close(module_info[0])
+                    _load_plugin(plugin_name, type="vim")
+                except NfvoException as e:
                     if ignore_errors:
-                        logger.error("Unknown vim type '{}'. Can not open file '{}.py'; {}: {}".format(
-                                            vim["type"], module, type(e).__name__, str(e)))
+                        logger.error("{}".format(e))
                         continue
-                    raise NfvoException("Unknown vim type '{}'. Can not open file '{}.py'; {}: {}".format(
-                                            vim["type"], module, type(e).__name__, str(e)), httperrors.Bad_Request)
-
+                    else:
+                        raise
             try:
                 if 'datacenter_tenant_id' in vim:
                     thread_id = vim["datacenter_tenant_id"]
@@ -418,7 +421,7 @@
                     persistent_info = {}
                 #if not tenant:
                 #    return -httperrors.Bad_Request, "You must provide a valid tenant name or uuid for VIM  %s" % ( vim["type"])
-                vim_dict[ vim['datacenter_id'] ] = vimconn_imported[ vim["type"] ].vimconnector(
+                vim_dict[vim['datacenter_id']] = plugins[plugin_name].vimconnector(
                                 uuid=vim['datacenter_id'], name=vim['datacenter_name'],
                                 tenant_id=vim.get('vim_tenant_id',vim_tenant),
                                 tenant_name=vim.get('vim_tenant_name',vim_tenant_name),
@@ -541,7 +544,7 @@
     for internal_connection in vnf_descriptor["vnf"].get("internal-connections",() ):
         if internal_connection["name"] in name_list:
             raise NfvoException(
-                "Error at vnf:internal-connections:name, value '%s' already used as an internal-connection".format(
+                "Error at vnf:internal-connections:name, value '{}' already used as an internal-connection".format(
                     internal_connection["name"]),
                 httperrors.Bad_Request)
         name_list.append(internal_connection["name"])
@@ -619,7 +622,7 @@
             image_mano_id = mydb.new_row('images', temp_image_dict, add_uuid=True)
             rollback_list.append({"where":"mano", "what":"image","uuid":image_mano_id})
     #create image at every vim
-    for vim_id,vim in vims.iteritems():
+    for vim_id,vim in vims.items():
         datacenter_vim_id = vim["config"]["datacenter_tenant_id"]
         image_created="false"
         #look at database
@@ -928,7 +931,7 @@
         vnfd_descriptor_list = vnfd_catalog_descriptor.get("vnfd")
         if not vnfd_descriptor_list:
             vnfd_descriptor_list = vnfd_catalog_descriptor.get("vnfd:vnfd")
-        for vnfd_yang in myvnfd.vnfd_catalog.vnfd.itervalues():
+        for vnfd_yang in myvnfd.vnfd_catalog.vnfd.values():
             vnfd = vnfd_yang.get()
 
             # table vnf
@@ -953,7 +956,7 @@
 
             # table ip_profiles (ip-profiles)
             ip_profile_name2db_table_index = {}
-            for ip_profile in vnfd.get("ip-profiles").itervalues():
+            for ip_profile in vnfd.get("ip-profiles").values():
                 db_ip_profile = {
                     "ip_version": str(ip_profile["ip-profile-params"].get("ip-version", "ipv4")),
                     "subnet_address": str(ip_profile["ip-profile-params"].get("subnet-address")),
@@ -963,7 +966,7 @@
                     "dhcp_count": str(ip_profile["ip-profile-params"]["dhcp-params"].get("count")),
                 }
                 dns_list = []
-                for dns in ip_profile["ip-profile-params"]["dns-server"].itervalues():
+                for dns in ip_profile["ip-profile-params"]["dns-server"].values():
                     dns_list.append(str(dns.get("address")))
                 db_ip_profile["dns_address"] = ";".join(dns_list)
                 if ip_profile["ip-profile-params"].get('security-group'):
@@ -974,7 +977,7 @@
 
             # table nets (internal-vld)
             net_id2uuid = {}  # for mapping interface with network
-            for vld in vnfd.get("internal-vld").itervalues():
+            for vld in vnfd.get("internal-vld").values():
                 net_uuid = str(uuid4())
                 uuid_list.append(net_uuid)
                 db_net = {
@@ -997,7 +1000,7 @@
                                             httperrors.Bad_Request)
                     db_ip_profiles[ip_profile_name2db_table_index[ip_profile_name]]["net_id"] = net_uuid
                 else:  #check no ip-address has been defined
-                    for icp in vld.get("internal-connection-point").itervalues():
+                    for icp in vld.get("internal-connection-point").values():
                         if icp.get("ip-address"):
                             raise NfvoException("Error at 'vnfd[{}]':'vld[{}]':'internal-connection-point[{}]' "
                                             "contains an ip-address but no ip-profile has been defined at VLD".format(
@@ -1015,7 +1018,7 @@
             vdu_id2uuid = {}
             vdu_id2db_table_index = {}
             mgmt_access = {}
-            for vdu in vnfd.get("vdu").itervalues():
+            for vdu in vnfd.get("vdu").values():
 
                 for vdu_descriptor in vnfd_descriptor["vdu"]:
                     if vdu_descriptor["id"] == str(vdu["id"]):
@@ -1048,7 +1051,7 @@
                     db_vm["image_id"] = image_uuid
                 if vdu.get("alternative-images"):
                     vm_alternative_images = []
-                    for alt_image in vdu.get("alternative-images").itervalues():
+                    for alt_image in vdu.get("alternative-images").values():
                         db_image = {}
                         image_uuid = _lookfor_or_create_image(db_image, mydb, alt_image)
                         if not image_uuid:
@@ -1109,7 +1112,7 @@
                             boot_data['boot-data-drive'] = True
                     if vdu["supplemental-boot-data"].get('config-file'):
                         om_cfgfile_list = list()
-                        for custom_config_file in vdu["supplemental-boot-data"]['config-file'].itervalues():
+                        for custom_config_file in vdu["supplemental-boot-data"]['config-file'].values():
                             # TODO Where this file content is present???
                             cfg_source = str(custom_config_file["source"])
                             om_cfgfile_list.append({"dest": custom_config_file["dest"],
@@ -1123,8 +1126,8 @@
 
                 # table interfaces (internal/external interfaces)
                 flavor_epa_interfaces = []
-                # for iface in chain(vdu.get("internal-interface").itervalues(), vdu.get("external-interface").itervalues()):
-                for iface in vdu.get("interface").itervalues():
+                # for iface in chain(vdu.get("internal-interface").values(), vdu.get("external-interface").values()):
+                for iface in vdu.get("interface").values():
                     flavor_epa_interface = {}
                     iface_uuid = str(uuid4())
                     uuid_list.append(iface_uuid)
@@ -1140,7 +1143,7 @@
 
                     if iface.get("virtual-interface").get("bandwidth"):
                         bps = int(iface.get("virtual-interface").get("bandwidth"))
-                        db_interface["bw"] = int(math.ceil(bps/1000000.0))
+                        db_interface["bw"] = int(math.ceil(bps / 1000000.0))
                         flavor_epa_interface["bandwidth"] = "{} Mbps".format(db_interface["bw"])
 
                     if iface.get("virtual-interface").get("type") == "OM-MGMT":
@@ -1203,8 +1206,8 @@
                                 raise KeyError("does not exist at vdu:internal-connection-point")
                             icp = None
                             icp_vld = None
-                            for vld in vnfd.get("internal-vld").itervalues():
-                                for cp in vld.get("internal-connection-point").itervalues():
+                            for vld in vnfd.get("internal-vld").values():
+                                for cp in vld.get("internal-connection-point").values():
                                     if cp.get("id-ref") == iface.get("internal-connection-point-ref"):
                                         if icp:
                                             raise KeyError("is referenced by more than one 'internal-vld'")
@@ -1254,7 +1257,7 @@
                     if vdu["guest-epa"].get("numa-node-policy"):  # TODO or dedicated_int:
                         numa_node_policy = vdu["guest-epa"].get("numa-node-policy")
                         if numa_node_policy.get("node"):
-                            numa_node = numa_node_policy["node"].values()[0]
+                            numa_node = next(iter(numa_node_policy["node"].values()))
                             if numa_node.get("num-cores"):
                                 numa["cores"] = numa_node["num-cores"]
                                 epa_vcpu_set = True
@@ -1264,7 +1267,7 @@
                                     epa_vcpu_set = True
                                 if len(numa_node["paired-threads"].get("paired-thread-ids")):
                                     numa["paired-threads-id"] = []
-                                    for pair in numa_node["paired-threads"]["paired-thread-ids"].itervalues():
+                                    for pair in numa_node["paired-threads"]["paired-thread-ids"].values():
                                         numa["paired-threads-id"].append(
                                             (str(pair["thread-a"]), str(pair["thread-b"]))
                                         )
@@ -1322,9 +1325,9 @@
                 db_vm["flavor_id"] = flavor_uuid
 
             # VNF affinity and antiaffinity
-            for pg in vnfd.get("placement-groups").itervalues():
+            for pg in vnfd.get("placement-groups").values():
                 pg_name = get_str(pg, "name", 255)
-                for vdu in pg.get("member-vdus").itervalues():
+                for vdu in pg.get("member-vdus").values():
                     vdu_id = get_str(vdu, "member-vdu-ref", 255)
                     if vdu_id not in vdu_id2db_table_index:
                         raise NfvoException("Error. Invalid VNF descriptor at 'vnfd[{vnf}]':'placement-groups[{pg}]':"
@@ -1343,8 +1346,8 @@
                                         "'{vdu}'. Reference to a non-existing vdu".format(
                                             vnf=vnfd_id, vdu=mgmt_vdu_id),
                                         httperrors.Bad_Request)
-                mgmt_access["vm_id"] = vdu_id2uuid[vnfd["mgmt-interface"]["vdu-id"]]
-                mgmt_access["vdu-id"] = vnfd["mgmt-interface"]["vdu-id"]
+                mgmt_access["vm_id"] = vdu_id2uuid[mgmt_vdu_id]
+                mgmt_access["vdu-id"] = mgmt_vdu_id
                 # if only one cp is defined by this VDU, mark this interface as of type "mgmt"
                 if vdu_id2cp_name.get(mgmt_vdu_id):
                     if cp_name2db_interface[vdu_id2cp_name[mgmt_vdu_id]]:
@@ -1447,7 +1450,7 @@
             VNFCitem={}
             VNFCitem["name"] = vnfc['name']
             VNFCitem["availability_zone"] = vnfc.get('availability_zone')
-            VNFCitem["description"] = vnfc.get("description", 'VM %s of the VNF %s' %(vnfc['name'],vnf_name))
+            VNFCitem["description"] = vnfc.get("description", 'VM {} of the VNF {}'.format(vnfc['name'],vnf_name))
 
             #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
 
@@ -1584,7 +1587,7 @@
         for vnfc in vnf_descriptor['vnf']['VNFC']:
             VNFCitem={}
             VNFCitem["name"] = vnfc['name']
-            VNFCitem["description"] = vnfc.get("description", 'VM %s of the VNF %s' %(vnfc['name'],vnf_name))
+            VNFCitem["description"] = vnfc.get("description", 'VM {} of the VNF {}'.format(vnfc['name'],vnf_name))
 
             #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
 
@@ -1691,7 +1694,7 @@
 
     vnf_id = vnf["uuid"]
     filter_keys = ('uuid', 'name', 'description', 'public', "tenant_id", "osm_id", "created_at")
-    filtered_content = dict( (k,v) for k,v in vnf.iteritems() if k in filter_keys )
+    filtered_content = dict( (k,v) for k,v in vnf.items() if k in filter_keys )
     #change_keys_http2db(filtered_content, http2db_vnf, reverse=True)
     data={'vnf' : filtered_content}
     #GET VM
@@ -1837,7 +1840,7 @@
             mydb.delete_row_by_id('images', image)
         except db_base_Exception as e:
             logger.error("delete_vnf_error. Not possible to get image details and delete '%s'. %s", image, str(e))
-            undeletedItems.append("image %s" % image)
+            undeletedItems.append("image {}".format(image))
 
     return vnf_id + " " + vnf["name"]
     #if undeletedItems:
@@ -1850,8 +1853,8 @@
     if result < 0:
         return result, vims
     elif result == 0:
-        return -httperrors.Not_Found, "datacenter '%s' not found" % datacenter_name
-    myvim = vims.values()[0]
+        return -httperrors.Not_Found, "datacenter '{}' not found".format(datacenter_name)
+    myvim = next(iter(vims.values()))
     result,servers =  myvim.get_hosts_info()
     if result < 0:
         return result, servers
@@ -1866,7 +1869,7 @@
     elif len(vims)>1:
         #print "nfvo.datacenter_action() error. Several datacenters found"
         raise NfvoException("More than one datacenters found, try to identify with uuid", httperrors.Conflict)
-    myvim = vims.values()[0]
+    myvim = next(iter(vims.values()))
     try:
         hosts =  myvim.get_hosts()
         logger.debug('VIM hosts response: '+ yaml.safe_dump(hosts, indent=4, default_flow_style=False))
@@ -2081,7 +2084,8 @@
             for net_key in other_nets.keys():
                 if con[index][0]==net_key:
                     if other_net_index>=0:
-                        error_text="There is some interface connected both to net '%s' and net '%s'" % (con[other_net_index][0], net_key)
+                        error_text = "There is some interface connected both to net '{}' and net '{}'".format(
+                            con[other_net_index][0], net_key)
                         #print "nfvo.new_scenario " + error_text
                         raise NfvoException(error_text, httperrors.Bad_Request)
                     else:
@@ -2117,7 +2121,7 @@
                 net_type_data=False
                 net_target = "__-__net"+str(net_nb)
                 net_list[net_target] = {'name': conections_list_name[net_nb],  #"net-"+str(net_nb),
-                    'description':"net-%s in scenario %s" %(net_nb,topo['name']),
+                    'description':"net-{} in scenario {}".format(net_nb,topo['name']),
                     'external':False}
                 for iface in con:
                     vnfs[ iface[0] ]['ifaces'][ iface[1] ]['net_key'] = net_target
@@ -2127,7 +2131,7 @@
                     else:
                         net_type_data = True
                 if net_type_bridge and net_type_data:
-                    error_text = "Error connection interfaces of bridge type with data type. Firs node %s, iface %s" % (iface[0], iface[1])
+                    error_text = "Error connection interfaces of bridge type with data type. Firs node {}, iface {}".format(iface[0], iface[1])
                     #print "nfvo.new_scenario " + error_text
                     raise NfvoException(error_text, httperrors.Bad_Request)
                 elif net_type_bridge:
@@ -2137,7 +2141,7 @@
                 net_list[net_target]['type'] = type_
                 net_nb+=1
         except Exception:
-            error_text = "Error connection node %s : %s does not match any VNF or interface" % (iface[0], iface[1])
+            error_text = "Error connection node {} : {} does not match any VNF or interface".format(iface[0], iface[1])
             #print "nfvo.new_scenario " + error_text
             #raise e
             raise NfvoException(error_text, httperrors.Bad_Request)
@@ -2192,7 +2196,7 @@
         tenant_id=None
 
     # 1: Check that VNF are present at database table vnfs and update content into scenario dict
-    for name,vnf in scenario["vnfs"].iteritems():
+    for name,vnf in scenario["vnfs"].items():
         where = {"OR": {"tenant_id": tenant_id, 'public': "true"}}
         error_text = ""
         error_pos = "'scenario':'vnfs':'" + name + "'"
@@ -2326,7 +2330,7 @@
         db_ip_profiles_index = 0
         uuid_list = []
         nsd_uuid_list = []
-        for nsd_yang in mynsd.nsd_catalog.nsd.itervalues():
+        for nsd_yang in mynsd.nsd_catalog.nsd.values():
             nsd = nsd_yang.get()
 
             # table scenarios
@@ -2348,7 +2352,7 @@
             # table sce_vnfs (constituent-vnfd)
             vnf_index2scevnf_uuid = {}
             vnf_index2vnf_uuid = {}
-            for vnf in nsd.get("constituent-vnfd").itervalues():
+            for vnf in nsd.get("constituent-vnfd").values():
                 existing_vnf = mydb.get_rows(FROM="vnfs", WHERE={'osm_id': str(vnf["vnfd-id-ref"])[:255],
                                                                       'tenant_id': tenant_id})
                 if not existing_vnf:
@@ -2373,7 +2377,7 @@
 
             # table ip_profiles (ip-profiles)
             ip_profile_name2db_table_index = {}
-            for ip_profile in nsd.get("ip-profiles").itervalues():
+            for ip_profile in nsd.get("ip-profiles").values():
                 db_ip_profile = {
                     "ip_version": str(ip_profile["ip-profile-params"].get("ip-version", "ipv4")),
                     "subnet_address": str(ip_profile["ip-profile-params"].get("subnet-address")),
@@ -2383,7 +2387,7 @@
                     "dhcp_count": str(ip_profile["ip-profile-params"]["dhcp-params"].get("count")),
                 }
                 dns_list = []
-                for dns in ip_profile["ip-profile-params"]["dns-server"].itervalues():
+                for dns in ip_profile["ip-profile-params"]["dns-server"].values():
                     dns_list.append(str(dns.get("address")))
                 db_ip_profile["dns_address"] = ";".join(dns_list)
                 if ip_profile["ip-profile-params"].get('security-group'):
@@ -2393,7 +2397,7 @@
                 db_ip_profiles.append(db_ip_profile)
 
             # table sce_nets (internal-vld)
-            for vld in nsd.get("vld").itervalues():
+            for vld in nsd.get("vld").values():
                 sce_net_uuid = str(uuid4())
                 uuid_list.append(sce_net_uuid)
                 db_sce_net = {
@@ -2431,7 +2435,7 @@
 
                 
                 # table sce_interfaces (vld:vnfd-connection-point-ref)
-                for iface in vld.get("vnfd-connection-point-ref").itervalues():
+                for iface in vld.get("vnfd-connection-point-ref").values():
                     # Check if there are VDUs in the descriptor
                     vnf_index = str(iface['member-vnf-index-ref'])
                     existing_vdus = mydb.get_rows(SELECT=('vms.uuid'), FROM="vms", WHERE={'vnf_id': vnf_index2vnf_uuid[vnf_index]})
@@ -2476,7 +2480,7 @@
                             db_sce_net["type"] = "bridge"
 
             # table sce_vnffgs (vnffgd)
-            for vnffg in nsd.get("vnffgd").itervalues():
+            for vnffg in nsd.get("vnffgd").values():
                 sce_vnffg_uuid = str(uuid4())
                 uuid_list.append(sce_vnffg_uuid)
                 db_sce_vnffg = {
@@ -2489,7 +2493,7 @@
                 db_sce_vnffgs.append(db_sce_vnffg)
 
                 # deal with rsps
-                for rsp in vnffg.get("rsp").itervalues():
+                for rsp in vnffg.get("rsp").values():
                     sce_rsp_uuid = str(uuid4())
                     uuid_list.append(sce_rsp_uuid)
                     db_sce_rsp = {
@@ -2499,7 +2503,7 @@
                         "id": get_str(rsp, "id", 255), # only useful to link with classifiers; will be removed later in the code
                     }
                     db_sce_rsps.append(db_sce_rsp)
-                    for iface in rsp.get("vnfd-connection-point-ref").itervalues():
+                    for iface in rsp.get("vnfd-connection-point-ref").values():
                         vnf_index = str(iface['member-vnf-index-ref'])
                         if_order = int(iface['order'])
                         # check correct parameters
@@ -2551,7 +2555,7 @@
                         db_sce_rsp_hops.append(db_sce_rsp_hop)
 
                 # deal with classifiers
-                for classifier in vnffg.get("classifier").itervalues():
+                for classifier in vnffg.get("classifier").values():
                     sce_classifier_uuid = str(uuid4())
                     uuid_list.append(sce_classifier_uuid)
 
@@ -2589,7 +2593,7 @@
                     db_sce_classifier["sce_rsp_id"] = rsp["uuid"]
                     db_sce_classifiers.append(db_sce_classifier)
 
-                    for match in classifier.get("match-attributes").itervalues():
+                    for match in classifier.get("match-attributes").values():
                         sce_classifier_match_uuid = str(uuid4())
                         uuid_list.append(sce_classifier_match_uuid)
                         db_sce_classifier_match = {
@@ -2667,7 +2671,7 @@
         for sce_net in scenarioDict['nets']:
             #print "Net name: %s. Description: %s" % (sce_net["name"], sce_net["description"])
 
-            myNetName = "%s.%s" % (instance_scenario_name, sce_net['name'])
+            myNetName = "{}.{}".format(instance_scenario_name, sce_net['name'])
             myNetName = myNetName[0:255] #limit length
             myNetType = sce_net['type']
             myNetDict = {}
@@ -2688,7 +2692,8 @@
                 sce_net["created"] = True
             else:
                 if sce_net['vim_id'] == None:
-                    error_text = "Error, datacenter '%s' does not have external network '%s'." % (datacenter_name, sce_net['name'])
+                    error_text = "Error, datacenter '{}' does not have external network '{}'.".format(
+                        datacenter_name, sce_net['name'])
                     _, message = rollback(mydb, vims, rollbackList)
                     logger.error("nfvo.start_scenario: %s", error_text)
                     raise NfvoException(error_text, httperrors.Bad_Request)
@@ -2702,7 +2707,7 @@
             for net in sce_vnf['nets']:
                 #print "Net name: %s. Description: %s" % (net["name"], net["description"])
 
-                myNetName = "%s.%s" % (instance_scenario_name,net['name'])
+                myNetName = "{}.{}".format(instance_scenario_name,net['name'])
                 myNetName = myNetName[0:255] #limit length
                 myNetType = net['type']
                 myNetDict = {}
@@ -2761,7 +2766,7 @@
                 #create flavor at vim in case it not exist
                 flavor_dict = mydb.get_table_by_uuid_name("flavors", vm['flavor_id'])
                 if flavor_dict['extended']!=None:
-                    flavor_dict['extended']= yaml.load(flavor_dict['extended'])
+                    flavor_dict['extended']= yaml.load(flavor_dict['extended'], Loader=yaml.Loader)
                 flavor_id = create_or_use_flavor(mydb, vims, flavor_dict, [], True)
                 vm['vim_flavor_id'] = flavor_id
 
@@ -2792,7 +2797,8 @@
                     if netDict["use"]=="data" and not netDict.get("type"):
                         #print "netDict", netDict
                         #print "iface", iface
-                        e_text = "Cannot determine the interface type PF or VF of VNF '%s' VM '%s' iface '%s'" %(sce_vnf['name'], vm['name'], iface['internal_name'])
+                        e_text = "Cannot determine the interface type PF or VF of VNF '{}' VM '{}' iface '{}'".format(
+                            sce_vnf['name'], vm['name'], iface['internal_name'])
                         if flavor_dict.get('extended')==None:
                             raise NfvoException(e_text  + "After database migration some information is not available. \
                                     Try to delete and create the scenarios and VNFs again", httperrors.Conflict)
@@ -3021,13 +3027,14 @@
     elif len(vims)>1:
         #print "nfvo.datacenter_action() error. Several datacenters found"
         raise NfvoException("More than one datacenters found, try to identify with uuid", httperrors.Conflict)
-    return vims.keys()[0], vims.values()[0]
+    for vim_id, vim_content in vims.items():
+        return vim_id, vim_content
 
 
 def update(d, u):
     """Takes dict d and updates it with the values in dict u.
        It merges all depth levels"""
-    for k, v in u.iteritems():
+    for k, v in u.items():
         if isinstance(v, collections.Mapping):
             r = update(d.get(k, {}), v)
             d[k] = r
@@ -3036,6 +3043,14 @@
     return d
 
 
+def _get_wim(db, wim_account_id):
+    # get wim from wim_account
+    wim_accounts = db.get_rows(FROM='wim_accounts', WHERE={"uuid": wim_account_id})
+    if not wim_accounts:
+        raise NfvoException("Not found sdn id={}".format(wim_account_id), http_code=httperrors.Not_Found)
+    return wim_accounts[0]["wim_id"]
+
+
 def create_instance(mydb, tenant_id, instance_dict):
     # print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
     # logger.debug("Creating instance...")
@@ -3101,6 +3116,7 @@
     }
 
     # Auxiliary dictionaries from x to y
+    sce_net2wim_instance = {}
     sce_net2instance = {}
     net2task_id = {'scenario': {}}
     # Mapping between local networks and WIMs
@@ -3129,7 +3145,7 @@
     #               yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False))
     try:
         # 0 check correct parameters
-        for net_name, net_instance_desc in instance_dict.get("networks", {}).iteritems():
+        for net_name, net_instance_desc in instance_dict.get("networks", {}).items():
             for scenario_net in scenarioDict['nets']:
                 if net_name == scenario_net.get("name") or net_name == scenario_net.get("osm_id") or net_name == scenario_net.get("uuid"):
                     break
@@ -3155,7 +3171,7 @@
                     site_without_datacenter_field = True
                     site["datacenter"] = default_datacenter_id   # change name to id
 
-        for vnf_name, vnf_instance_desc in instance_dict.get("vnfs",{}).iteritems():
+        for vnf_name, vnf_instance_desc in instance_dict.get("vnfs",{}).items():
             for scenario_vnf in scenarioDict['vnfs']:
                 if vnf_name == scenario_vnf['member_vnf_index'] or vnf_name == scenario_vnf['uuid'] or vnf_name == scenario_vnf['name']:
                     break
@@ -3170,7 +3186,7 @@
                     myvim_threads_id[d], _ = get_vim_thread(mydb, tenant_id, vnf_instance_desc["datacenter"])
                 scenario_vnf["datacenter"] = vnf_instance_desc["datacenter"]
 
-            for net_id, net_instance_desc in vnf_instance_desc.get("networks", {}).iteritems():
+            for net_id, net_instance_desc in vnf_instance_desc.get("networks", {}).items():
                 for scenario_net in scenario_vnf['nets']:
                     if net_id == scenario_net['osm_id'] or net_id == scenario_net['uuid'] or net_id == scenario_net["name"]:
                         break
@@ -3196,14 +3212,14 @@
                         else:
                             update(scenario_net['provider-network'], provider_network_db)
 
-            for vdu_id, vdu_instance_desc in vnf_instance_desc.get("vdus", {}).iteritems():
+            for vdu_id, vdu_instance_desc in vnf_instance_desc.get("vdus", {}).items():
                 for scenario_vm in scenario_vnf['vms']:
                     if vdu_id == scenario_vm['osm_id'] or vdu_id == scenario_vm["name"]:
                         break
                 else:
                     raise NfvoException("Invalid vdu id or name '{}' at instance:vnfs:vdus".format(vdu_id), httperrors.Bad_Request)
                 scenario_vm["instance_parameters"] = vdu_instance_desc
-                for iface_id, iface_instance_desc in vdu_instance_desc.get("interfaces", {}).iteritems():
+                for iface_id, iface_instance_desc in vdu_instance_desc.get("interfaces", {}).items():
                     for scenario_interface in scenario_vm['interfaces']:
                         if iface_id == scenario_interface['internal_name'] or iface_id == scenario_interface["external_name"]:
                             scenario_interface.update(iface_instance_desc)
@@ -3217,8 +3233,7 @@
         # 0.2 merge instance information into scenario
         # Ideally, the operation should be as simple as: update(scenarioDict,instance_dict)
         # However, this is not possible yet.
-        for net_name, net_instance_desc in instance_dict.get("networks", {}).iteritems():
-
+        for net_name, net_instance_desc in instance_dict.get("networks", {}).items():
             for scenario_net in scenarioDict['nets']:
                 if net_name == scenario_net.get("name") or net_name == scenario_net.get("osm_id") or net_name == scenario_net.get("uuid"):
                     if "wim_account" in net_instance_desc and net_instance_desc["wim_account"] is not None:
@@ -3253,6 +3268,7 @@
         # 1. Creating new nets (sce_nets) in the VIM"
         number_mgmt_networks = 0
         db_instance_nets = []
+        db_instance_wim_nets = []
         for sce_net in scenarioDict['nets']:
 
             sce_net_uuid = sce_net.get('uuid', sce_net["name"])
@@ -3311,6 +3327,7 @@
                     if site.get("datacenter") and site["datacenter"] not in involved_datacenters:
                         involved_datacenters.append(site["datacenter"])
             sce_net2instance[sce_net_uuid] = {}
+            sce_net2wim_instance[sce_net_uuid] = {}
             net2task_id['scenario'][sce_net_uuid] = {}
 
             use_network = None
@@ -3419,6 +3436,41 @@
                 sce_net2instance[sce_net_uuid][datacenter_id] = net_uuid
                 if not related_network:   # all db_instance_nets will have same related
                     related_network = use_network or net_uuid
+                sdn_net_id = None
+                sdn_controller = vim.config.get('sdn-controller')
+                sce_net2wim_instance[sce_net_uuid][datacenter_id] = None
+                if sdn_controller and net_type in ("data", "ptp"):
+                    wim_id = _get_wim(mydb, sdn_controller)
+                    sdn_net_id = str(uuid4())
+                    sce_net2wim_instance[sce_net_uuid][datacenter_id] = sdn_net_id
+                    task_extra["sdn_net_id"] = sdn_net_id
+                    db_instance_wim_nets.append({
+                        "uuid": sdn_net_id,
+                        "instance_scenario_id": instance_uuid,
+                        "sce_net_id": sce_net.get("uuid"),
+                        "wim_id": wim_id,
+                        "wim_account_id": sdn_controller,
+                        'status': 'BUILD',  # if create_network else "ACTIVE"
+                        "related": related_network,
+                        'multipoint': True if net_type=="data" else False,
+                        "created": create_network, # TODO py3
+                        "sdn": True,
+                    })
+                    task_wim_extra = {"params": [net_type, wim_account_name]}
+                    db_vim_action = {
+                        "instance_action_id": instance_action_id,
+                        "status": "SCHEDULED",
+                        "task_index": task_index,
+                        # "datacenter_vim_id": myvim_thread_id,
+                        "wim_account_id": sdn_controller,
+                        "action": task_action,
+                        "item": "instance_wim_nets",
+                        "item_id": sdn_net_id,
+                        "related": related_network,
+                        "extra": yaml.safe_dump(task_wim_extra, default_flow_style=True, width=256)
+                    }
+                    task_index += 1
+                    db_vim_actions.append(db_vim_action)
                 db_net = {
                     "uuid": net_uuid,
                     "osm_id": sce_net.get("osm_id") or sce_net["name"],
@@ -3430,7 +3482,8 @@
                     "created": create_network,
                     'datacenter_id': datacenter_id,
                     'datacenter_tenant_id': myvim_thread_id,
-                    'status': 'BUILD' #  if create_network else "ACTIVE"
+                    'status': 'BUILD', #  if create_network else "ACTIVE"
+                    'sdn_net_id': sdn_net_id,
                 }
                 db_instance_nets.append(db_net)
                 db_vim_action = {
@@ -3477,6 +3530,7 @@
             "task_index": task_index,
             "uuid_list": uuid_list,
             "db_instance_nets": db_instance_nets,
+            "db_instance_wim_nets": db_instance_wim_nets,
             "db_vim_actions": db_vim_actions,
             "db_ip_profiles": db_ip_profiles,
             "db_instance_vnfs": db_instance_vnfs,
@@ -3484,6 +3538,7 @@
             "db_instance_interfaces": db_instance_interfaces,
             "net2task_id": net2task_id,
             "sce_net2instance": sce_net2instance,
+            "sce_net2wim_instance": sce_net2wim_instance,
         }
         # sce_vnf_list = sorted(scenarioDict['vnfs'], key=lambda k: k['name'])
         for sce_vnf in scenarioDict.get('vnfs', ()):  # sce_vnf_list:
@@ -3681,7 +3736,7 @@
             {"instance_sfs": db_instance_sfs},
             {"instance_classifications": db_instance_classifications},
             {"instance_sfps": db_instance_sfps},
-            {"instance_wim_nets": wan_links},
+            {"instance_wim_nets": db_instance_wim_nets + wan_links},
             {"vim_wim_actions": db_vim_actions + wim_actions}
         ]
 
@@ -3696,13 +3751,13 @@
         returned_instance = mydb.get_instance_scenario(instance_uuid)
         returned_instance["action_id"] = instance_action_id
         return returned_instance
-    except (NfvoException, vimconn.vimconnException, wimconn.WimConnectorError, db_base_Exception) as e:
+    except (NfvoException, vimconn.vimconnException, sdnconn.SdnConnectorError, db_base_Exception) as e:
         message = rollback(mydb, myvims, rollbackList)
         if isinstance(e, db_base_Exception):
             error_text = "database Exception"
         elif isinstance(e, vimconn.vimconnException):
             error_text = "VIM Exception"
-        elif isinstance(e, wimconn.WimConnectorError):
+        elif isinstance(e, sdnconn.SdnConnectorError):
             error_text = "WIM Exception"
         else:
             error_text = "Exception"
@@ -3725,6 +3780,7 @@
     task_index = params_out["task_index"]
     uuid_list = params_out["uuid_list"]
     db_instance_nets = params_out["db_instance_nets"]
+    db_instance_wim_nets = params_out["db_instance_wim_nets"]
     db_vim_actions = params_out["db_vim_actions"]
     db_ip_profiles = params_out["db_ip_profiles"]
     db_instance_vnfs = params_out["db_instance_vnfs"]
@@ -3732,15 +3788,18 @@
     db_instance_interfaces = params_out["db_instance_interfaces"]
     net2task_id = params_out["net2task_id"]
     sce_net2instance = params_out["sce_net2instance"]
+    sce_net2wim_instance = params_out["sce_net2wim_instance"]
 
     vnf_net2instance = {}
 
     # 2. Creating new nets (vnf internal nets) in the VIM"
     # For each vnf net, we create it and we add it to instanceNetlist.
     if sce_vnf.get("datacenter"):
+        vim = myvims[sce_vnf["datacenter"]]
         datacenter_id = sce_vnf["datacenter"]
         myvim_thread_id = myvim_threads_id[sce_vnf["datacenter"]]
     else:
+        vim = myvims[default_datacenter_id]
         datacenter_id = default_datacenter_id
         myvim_thread_id = myvim_threads_id[default_datacenter_id]
     for net in sce_vnf['nets']:
@@ -3757,12 +3816,29 @@
             vnf_net2instance[sce_vnf['uuid']] = {}
         if sce_vnf['uuid'] not in net2task_id:
             net2task_id[sce_vnf['uuid']] = {}
-        net2task_id[sce_vnf['uuid']][net['uuid']] = task_index
 
         # fill database content
         net_uuid = str(uuid4())
         uuid_list.append(net_uuid)
         vnf_net2instance[sce_vnf['uuid']][net['uuid']] = net_uuid
+
+        sdn_controller = vim.config.get('sdn-controller')
+        sdn_net_id = None
+        if sdn_controller and net_type in ("data", "ptp"):
+            wim_id = _get_wim(mydb, sdn_controller)
+            sdn_net_id = str(uuid4())
+            db_instance_wim_nets.append({
+                "uuid": sdn_net_id,
+                "instance_scenario_id": instance_uuid,
+                "wim_id": wim_id,
+                "wim_account_id": sdn_controller,
+                'status': 'BUILD',  # if create_network else "ACTIVE"
+                "related": net_uuid,
+                'multipoint': True if net_type == "data" else False,
+                "created": True,  # TODO py3
+                "sdn": True,
+            })
+
         db_net = {
             "uuid": net_uuid,
             "related": net_uuid,
@@ -3773,6 +3849,7 @@
             "created": True,
             'datacenter_id': datacenter_id,
             'datacenter_tenant_id': myvim_thread_id,
+            'sdn_net_id': sdn_net_id,
         }
         db_instance_nets.append(db_net)
 
@@ -3787,7 +3864,25 @@
         else:
             task_action = "CREATE"
             task_extra = {"params": (net_name, net_type, net.get('ip_profile', None))}
+        if sdn_net_id:
+            task_extra["sdn_net_id"] = sdn_net_id
 
+        if sdn_net_id:
+            task_wim_extra = {"params": [net_type, None]}
+            db_vim_action = {
+                "instance_action_id": instance_action_id,
+                "status": "SCHEDULED",
+                "task_index": task_index,
+                # "datacenter_vim_id": myvim_thread_id,
+                "wim_account_id": sdn_controller,
+                "action": task_action,
+                "item": "instance_wim_nets",
+                "item_id": sdn_net_id,
+                "related": net_uuid,
+                "extra": yaml.safe_dump(task_wim_extra, default_flow_style=True, width=256)
+            }
+            task_index += 1
+            db_vim_actions.append(db_vim_action)
         db_vim_action = {
             "instance_action_id": instance_action_id,
             "task_index": task_index,
@@ -3799,6 +3894,7 @@
             "related": net_uuid,
             "extra": yaml.safe_dump(task_extra, default_flow_style=True, width=256)
         }
+        net2task_id[sce_vnf['uuid']][net['uuid']] = task_index
         task_index += 1
         db_vim_actions.append(db_vim_action)
 
@@ -3885,7 +3981,7 @@
         # create flavor at vim in case it not exist
         flavor_dict = mydb.get_table_by_uuid_name("flavors", vm['flavor_id'])
         if flavor_dict['extended'] != None:
-            flavor_dict['extended'] = yaml.load(flavor_dict['extended'])
+            flavor_dict['extended'] = yaml.load(flavor_dict['extended'], Loader=yaml.Loader)
         flavor_id = create_or_use_flavor(mydb, {datacenter_id: vim}, flavor_dict, rollbackList, True)
 
         # Obtain information for additional disks
@@ -3894,11 +3990,11 @@
         if not extended_flavor_dict:
             raise NfvoException("flavor '{}' not found".format(flavor_id), httperrors.Not_Found)
 
-        # extended_flavor_dict_yaml = yaml.load(extended_flavor_dict[0])
+        # extended_flavor_dict_yaml = yaml.load(extended_flavor_dict[0], Loader=yaml.Loader)
         myVMDict['disks'] = None
         extended_info = extended_flavor_dict[0]['extended']
         if extended_info != None:
-            extended_flavor_dict_yaml = yaml.load(extended_info)
+            extended_flavor_dict_yaml = yaml.load(extended_info, Loader=yaml.Loader)
             if 'disks' in extended_flavor_dict_yaml:
                 myVMDict['disks'] = extended_flavor_dict_yaml['disks']
                 if vm.get("instance_parameters") and vm["instance_parameters"].get("devices"):
@@ -3972,6 +4068,7 @@
                         netDict['net_id'] = "TASK-{}".format(
                             net2task_id['scenario'][vnf_iface['sce_net_id']][datacenter_id])
                         instance_net_id = sce_net2instance[vnf_iface['sce_net_id']][datacenter_id]
+                        instance_wim_net_id = sce_net2wim_instance[vnf_iface['sce_net_id']][datacenter_id]
                         task_depends_on.append(net2task_id['scenario'][vnf_iface['sce_net_id']][datacenter_id])
                         break
             else:
@@ -3986,9 +4083,11 @@
                 # "uuid"
                 # 'instance_vm_id': instance_vm_uuid,
                 "instance_net_id": instance_net_id,
+                "instance_wim_net_id": instance_wim_net_id,
                 'interface_id': iface['uuid'],
                 # 'vim_interface_id': ,
                 'type': 'external' if iface['external_name'] is not None else 'internal',
+                'model': iface['model'],
                 'ip_address': iface.get('ip_address'),
                 'mac_address': iface.get('mac'),
                 'floating_ip': int(iface.get('floating-ip', False)),
@@ -4138,7 +4237,7 @@
                 logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sfp["datacenter_id"], sfp["datacenter_tenant_id"]))
                 myvims[datacenter_key] = None
             else:
-                myvims[datacenter_key] = vims.values()[0]
+                myvims[datacenter_key] = next(iter(vims.values()))
         myvim = myvims[datacenter_key]
         myvim_thread = myvim_threads[datacenter_key]
 
@@ -4177,7 +4276,7 @@
                                                                                                classification["datacenter_tenant_id"]))
                 myvims[datacenter_key] = None
             else:
-                myvims[datacenter_key] = vims.values()[0]
+                myvims[datacenter_key] = next(iter(vims.values()))
         myvim = myvims[datacenter_key]
         myvim_thread = myvim_threads[datacenter_key]
 
@@ -4217,7 +4316,7 @@
                 logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sf["datacenter_id"], sf["datacenter_tenant_id"]))
                 myvims[datacenter_key] = None
             else:
-                myvims[datacenter_key] = vims.values()[0]
+                myvims[datacenter_key] = next(iter(vims.values()))
         myvim = myvims[datacenter_key]
         myvim_thread = myvim_threads[datacenter_key]
 
@@ -4256,7 +4355,7 @@
                 logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sfi["datacenter_id"], sfi["datacenter_tenant_id"]))
                 myvims[datacenter_key] = None
             else:
-                myvims[datacenter_key] = vims.values()[0]
+                myvims[datacenter_key] = next(iter(vims.values()))
         myvim = myvims[datacenter_key]
         myvim_thread = myvim_threads[datacenter_key]
 
@@ -4298,7 +4397,7 @@
                                                                                                sce_vnf["datacenter_tenant_id"]))
                 myvims[datacenter_key] = None
             else:
-                myvims[datacenter_key] = vims.values()[0]
+                myvims[datacenter_key] = next(iter(vims.values()))
         myvim = myvims[datacenter_key]
         myvim_thread = myvim_threads[datacenter_key]
 
@@ -4346,7 +4445,7 @@
                 logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net["datacenter_id"], net["datacenter_tenant_id"]))
                 myvims[datacenter_key] = None
             else:
-                myvims[datacenter_key] = vims.values()[0]
+                myvims[datacenter_key] = next(iter(vims.values()))
         myvim = myvims[datacenter_key]
         myvim_thread = myvim_threads[datacenter_key]
 
@@ -4375,6 +4474,23 @@
         }
         task_index += 1
         db_vim_actions.append(db_vim_action)
+    for sdn_net in instanceDict['sdn_nets']:
+        if not sdn_net["sdn"]:
+            continue
+        extra = {}
+        db_vim_action = {
+            "instance_action_id": instance_action_id,
+            "task_index": task_index,
+            "wim_account_id": sdn_net["wim_account_id"],
+            "action": "DELETE",
+            "status": "SCHEDULED",
+            "item": "instance_wim_nets",
+            "item_id": sdn_net["uuid"],
+            "related": sdn_net["related"],
+            "extra": yaml.safe_dump(extra, default_flow_style=True, width=256)
+        }
+        task_index += 1
+        db_vim_actions.append(db_vim_action)
 
     db_instance_action["number_tasks"] = task_index
 
@@ -4409,18 +4525,19 @@
     #obtain data
 
     instance_dict = mydb.get_instance_scenario(instance_id, tenant_id, verbose=True)
-    for net in instance_dict["nets"]:
-        if net.get("sdn_net_id"):
-            net_sdn = ovim.show_network(net["sdn_net_id"])
-            net["sdn_info"] = {
-                "admin_state_up": net_sdn.get("admin_state_up"),
-                "flows": net_sdn.get("flows"),
-                "last_error": net_sdn.get("last_error"),
-                "ports": net_sdn.get("ports"),
-                "type": net_sdn.get("type"),
-                "status": net_sdn.get("status"),
-                "vlan": net_sdn.get("vlan"),
-            }
+    # TODO py3
+    # for net in instance_dict["nets"]:
+    #     if net.get("sdn_net_id"):
+    #         net_sdn = ovim.show_network(net["sdn_net_id"])
+    #         net["sdn_info"] = {
+    #             "admin_state_up": net_sdn.get("admin_state_up"),
+    #             "flows": net_sdn.get("flows"),
+    #             "last_error": net_sdn.get("last_error"),
+    #             "ports": net_sdn.get("ports"),
+    #             "type": net_sdn.get("type"),
+    #             "status": net_sdn.get("status"),
+    #             "vlan": net_sdn.get("vlan"),
+    #         }
     return instance_dict
 
 @deprecated("Instance is automatically refreshed by vim_threads")
@@ -4452,7 +4569,7 @@
     #             logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"]))
     #             myvims[datacenter_key] = None
     #         else:
-    #             myvims[datacenter_key] = vims.values()[0]
+    #             myvims[datacenter_key] = next(iter(vims.values()))
     #     for vm in sce_vnf['vms']:
     #         vm_list[datacenter_key].append(vm['vim_vm_id'])
     #         vms_notupdated.append(vm["uuid"])
@@ -4471,7 +4588,7 @@
     #             logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net["datacenter_id"], net["datacenter_tenant_id"]))
     #             myvims[datacenter_key] = None
     #         else:
-    #             myvims[datacenter_key] = vims.values()[0]
+    #             myvims[datacenter_key] = next(iter(vims.values()))
     #
     #     net_list[datacenter_key].append(net['vim_net_id'])
     #     nets_notupdated.append(net["uuid"])
@@ -4597,7 +4714,7 @@
     vims = get_vim(mydb, nfvo_tenant, instanceDict['datacenter_id'])
     if len(vims) == 0:
         raise NfvoException("datacenter '{}' not found".format(str(instanceDict['datacenter_id'])), httperrors.Not_Found)
-    myvim = vims.values()[0]
+    myvim = next(iter(vims.values()))
     vm_result = {}
     vm_error = 0
     vm_ok = 0
@@ -4808,7 +4925,7 @@
             try:
                 if "add_public_key" in action_dict:
                     if sce_vnf.get('mgmt_access'):
-                        mgmt_access = yaml.load(sce_vnf['mgmt_access'])
+                        mgmt_access = yaml.load(sce_vnf['mgmt_access'], Loader=yaml.Loader)
                         if not input_vms and mgmt_access.get("vdu-id") != vm['vdu_osm_id']:
                             continue
                         default_user = mgmt_access.get("default-user")
@@ -4964,17 +5081,11 @@
     # Check that datacenter-type is correct
     datacenter_type = datacenter_descriptor.get("type", "openvim");
     # module_info = None
-    try:
-        module = "vimconn_" + datacenter_type
-        pkg = __import__("osm_ro." + module)
-        # vim_conn = getattr(pkg, module)
-        # module_info = imp.find_module(module, [__file__[:__file__.rfind("/")]])
-    except (IOError, ImportError):
-        # if module_info and module_info[0]:
-        #    file.close(module_info[0])
-        raise NfvoException("Incorrect datacenter type '{}'. Plugin '{}.py' not installed".format(datacenter_type,
-                                                                                                  module),
-                            httperrors.Bad_Request)
+
+    # load plugin
+    plugin_name = "rovim_" + datacenter_type
+    if plugin_name not in plugins:
+        _load_plugin(plugin_name, type="vim")
 
     datacenter_id = mydb.new_row("datacenters", datacenter_descriptor, add_uuid=True, confidential_data=True)
     if sdn_port_mapping:
@@ -5013,7 +5124,7 @@
                 config_text = datacenter.get("config")
                 if not config_text:
                     config_text = '{}'
-                config_dict = yaml.load(config_text)
+                config_dict = yaml.load(config_text, Loader=yaml.Loader)
                 config_dict.update(new_config_dict)
                 # delete null fields
                 for k in to_delete:
@@ -5126,8 +5237,7 @@
 
         # create thread
         thread_name = get_non_used_vim_name(datacenter_name, datacenter_id, tenant_dict['name'], tenant_dict['uuid'])
-        new_thread = vim_thread.vim_thread(task_lock, thread_name, datacenter_name, datacenter_tenant_id,
-                                           db=db, db_lock=db_lock, ovim=ovim)
+        new_thread = vim_thread(task_lock, plugins, thread_name, None, datacenter_tenant_id, db=db)
         new_thread.start()
         thread_id = datacenter_tenants_dict["uuid"]
         vim_threads["running"][thread_id] = new_thread
@@ -5156,7 +5266,7 @@
 
     update_ = {}
     if config:
-        original_config_dict = yaml.load(original_config)
+        original_config_dict = yaml.load(original_config, Loader=yaml.Loader)
         original_config_dict.update(config)
         update["config"] = yaml.safe_dump(original_config_dict, default_flow_style=True, width=256)
     if name:
@@ -5391,7 +5501,7 @@
     if not config:
         return None
 
-    return yaml.load(config).get('sdn-controller')
+    return yaml.load(config, Loader=yaml.Loader).get('sdn-controller')
 
 def vim_net_sdn_attach(mydb, tenant_id, datacenter, network_id, descriptor):
     try:
@@ -5507,12 +5617,12 @@
         if name and len(content)==1:
             return {item[:-1]: content[0]}
         elif name and len(content)==0:
-            raise NfvoException("No {} found with ".format(item[:-1]) + " and ".join(map(lambda x: str(x[0])+": "+str(x[1]), filter_dict.iteritems())),
+            raise NfvoException("No {} found with ".format(item[:-1]) + " and ".join(map(lambda x: str(x[0])+": "+str(x[1]), filter_dict.items())),
                  datacenter)
         else:
             return {item: content}
     except vimconn.vimconnException as e:
-        print "vim_action Not possible to get_%s_list from VIM: %s " % (item, str(e))
+        print("vim_action Not possible to get_{}_list from VIM: {} ".format(item, str(e)))
         raise NfvoException("Not possible to get_{}_list from VIM: {}".format(item, str(e)), e.http_code)
 
 
@@ -5525,7 +5635,7 @@
     #get uuid name
     content = vim_action_get(mydb, tenant_id, datacenter, item, name)
     logger.debug("vim_action_delete vim response: " + str(content))
-    items = content.values()[0]
+    items = next(iter(content.values()))
     if type(items)==list and len(items)==0:
         raise NfvoException("Not found " + item, httperrors.Not_Found)
     elif type(items)==list and len(items)>1:
@@ -5544,7 +5654,7 @@
                     port_list = ovim.get_ports(columns={'uuid'}, filter={'net_id': sdn_network_id})
                 except ovimException as e:
                     raise NfvoException(
-                        "ovimException obtaining external ports for net {}. ".format(network_id) + str(e),
+                        "ovimException obtaining external ports for net {}. ".format(sdn_network_id) + str(e),
                         httperrors.Internal_Server_Error)
 
                 # By calling one by one all ports to be detached we ensure that not only the external_ports get detached
@@ -5553,10 +5663,12 @@
 
                 #Delete from 'instance_nets' the correspondence between the vim-net-id and the sdn-net-id
                 try:
-                    mydb.delete_row(FROM='instance_nets', WHERE={'instance_scenario_id': None, 'sdn_net_id': sdn_network_id, 'vim_net_id': item_id})
+                    mydb.delete_row(FROM='instance_nets', WHERE={'instance_scenario_id': None,
+                                                                 'sdn_net_id': sdn_network_id,
+                                                                 'vim_net_id': item_id})
                 except db_base_Exception as e:
-                    raise NfvoException("Error deleting correspondence for VIM/SDN dataplane networks{}: ".format(correspondence) +
-                                        str(e), e.http_code)
+                    raise NfvoException("Error deleting correspondence for VIM/SDN dataplane networks{}: {}".format(
+                        item_id, e), e.http_code)
 
                 #Delete the SDN network
                 try:
@@ -5641,13 +5753,20 @@
     return vim_action_get(mydb, tenant_id, datacenter, item, content)
 
 def sdn_controller_create(mydb, tenant_id, sdn_controller):
-    data = ovim.new_of_controller(sdn_controller)
-    logger.debug('New SDN controller created with uuid {}'.format(data))
-    return data
+    wim_id = ovim.new_of_controller(sdn_controller)
+
+    thread_name = get_non_used_vim_name(sdn_controller['name'], wim_id, wim_id, None)
+    new_thread = vim_thread(task_lock, plugins, thread_name, wim_id, None, db=db)
+    new_thread.start()
+    thread_id = wim_id
+    vim_threads["running"][thread_id] = new_thread
+    logger.debug('New SDN controller created with uuid {}'.format(wim_id))
+    return wim_id
 
 def sdn_controller_update(mydb, tenant_id, controller_id, sdn_controller):
     data = ovim.edit_of_controller(controller_id, sdn_controller)
     msg = 'SDN controller {} updated'.format(data)
+    vim_threads["running"][controller_id].insert_task("reload")
     logger.debug(msg)
     return msg
 
@@ -5666,7 +5785,7 @@
     datacenters = mydb.get_rows(FROM='datacenters', SELECT=select_)
     for datacenter in datacenters:
         if datacenter['config']:
-            config = yaml.load(datacenter['config'])
+            config = yaml.load(datacenter['config'], Loader=yaml.Loader)
             if 'sdn-controller' in config and config['sdn-controller'] == controller_id:
                 raise NfvoException("SDN controller {} is in use by datacenter {}".format(controller_id, datacenter['uuid']), httperrors.Conflict)
 
@@ -5681,7 +5800,7 @@
         raise NfvoException("Datacenter {} not present in the database".format(datacenter_id), httperrors.Not_Found)
 
     try:
-        sdn_controller_id = yaml.load(controller[0]["config"])["sdn-controller"]
+        sdn_controller_id = yaml.load(controller[0]["config"], Loader=yaml.Loader)["sdn-controller"]
     except:
         raise NfvoException("The datacenter {} has not an SDN controller associated".format(datacenter_id), httperrors.Bad_Request)
 
@@ -5693,20 +5812,23 @@
         #element = {"ofc_id": sdn_controller_id, "region": datacenter_id, "switch_dpid": switch_dpid}
         element = dict()
         element["compute_node"] = compute_node["compute_node"]
-        for port in compute_node["ports"]:
-            pci = port.get("pci")
-            element["switch_port"] = port.get("switch_port")
-            element["switch_mac"] = port.get("switch_mac")
-            if not element["switch_port"] and not element["switch_mac"]:
-                raise NfvoException ("The mapping must contain 'switch_port' or 'switch_mac'", httperrors.Bad_Request)
-            for pci_expanded in utils.expand_brackets(pci):
-                element["pci"] = pci_expanded
-                maps.append(dict(element))
+        if compute_node["ports"]:
+            for port in compute_node["ports"]:
+                pci = port.get("pci")
+                element["switch_port"] = port.get("switch_port")
+                element["switch_mac"] = port.get("switch_mac")
+                if not element["switch_port"] and not element["switch_mac"]:
+                    raise NfvoException ("The mapping must contain 'switch_port' or 'switch_mac'", httperrors.Bad_Request)
+                for pci_expanded in utils.expand_brackets(pci):
+                    element["pci"] = pci_expanded
+                    maps.append(dict(element))
 
-    return ovim.set_of_port_mapping(maps, ofc_id=sdn_controller_id, switch_dpid=switch_dpid, region=datacenter_id)
+    out = ovim.set_of_port_mapping(maps, sdn_id=sdn_controller_id, switch_dpid=switch_dpid, vim_id=datacenter_id)
+    vim_threads["running"][sdn_controller_id].insert_task("reload")
+    return out
 
 def datacenter_sdn_port_mapping_list(mydb, tenant_id, datacenter_id):
-    maps = ovim.get_of_port_mappings(db_filter={"region": datacenter_id})
+    maps = ovim.get_of_port_mappings(db_filter={"datacenter_id": datacenter_id})
 
     result = {
         "sdn-controller": None,
@@ -5717,7 +5839,7 @@
 
     datacenter = mydb.get_table_by_uuid_name('datacenters', datacenter_id)
     if datacenter['config']:
-        config = yaml.load(datacenter['config'])
+        config = yaml.load(datacenter['config'], Loader=yaml.Loader)
         if 'sdn-controller' in config:
             controller_id = config['sdn-controller']
             sdn_controller = sdn_controller_list(mydb, tenant_id, controller_id)
@@ -5735,24 +5857,25 @@
 
     ports_correspondence_dict = dict()
     for link in maps:
-        if result["sdn-controller"] != link["ofc_id"]:
+        if result["sdn-controller"] != link["wim_id"]:
             raise NfvoException("The sdn-controller specified for different port mappings differ", httperrors.Internal_Server_Error)
         if result["dpid"] != link["switch_dpid"]:
             raise NfvoException("The dpid specified for different port mappings differ", httperrors.Internal_Server_Error)
+        link_config = link["service_mapping_info"]
         element = dict()
-        element["pci"] = link["pci"]
+        element["pci"] = link.get("device_interface_id")
         if link["switch_port"]:
             element["switch_port"] = link["switch_port"]
-        if link["switch_mac"]:
-            element["switch_mac"] = link["switch_mac"]
+        if link_config["switch_mac"]:
+            element["switch_mac"] = link_config.get("switch_mac")
 
-        if not link["compute_node"] in ports_correspondence_dict:
+        if not link.get("interface_id") in ports_correspondence_dict:
             content = dict()
-            content["compute_node"] = link["compute_node"]
+            content["compute_node"] = link.get("interface_id")
             content["ports"] = list()
-            ports_correspondence_dict[link["compute_node"]] = content
+            ports_correspondence_dict[link.get("interface_id")] = content
 
-        ports_correspondence_dict[link["compute_node"]]["ports"].append(element)
+        ports_correspondence_dict[link["interface_id"]]["ports"].append(element)
 
     for key in sorted(ports_correspondence_dict):
         result["ports_mapping"].append(ports_correspondence_dict[key])
@@ -5760,7 +5883,7 @@
     return result
 
 def datacenter_sdn_port_mapping_delete(mydb, tenant_id, datacenter_id):
-    return ovim.clear_of_port_mapping(db_filter={"region":datacenter_id})
+    return ovim.clear_of_port_mapping(db_filter={"datacenter_id":datacenter_id})
 
 def create_RO_keypair(tenant_id):
     """
diff --git a/osm_ro/nfvo_db.py b/RO/osm_ro/nfvo_db.py
similarity index 98%
rename from osm_ro/nfvo_db.py
rename to RO/osm_ro/nfvo_db.py
index eb72b13..df4f161 100644
--- a/osm_ro/nfvo_db.py
+++ b/RO/osm_ro/nfvo_db.py
@@ -27,16 +27,16 @@
 __author__="Alfonso Tierno, Gerardo Garcia, Pablo Montes"
 __date__ ="$28-aug-2014 10:05:01$"
 
-import db_base
+from osm_ro import db_base
 import MySQLdb as mdb
 import json
 import yaml
 import time
 #import sys, os
 
-from .db_base import retry, with_transaction
-from .http_tools import errors as httperrors
-from .utils import Attempt
+from osm_ro.db_base import retry, with_transaction
+from osm_ro.http_tools import errors as httperrors
+from osm_ro.utils import Attempt
 
 
 _ATTEMPT = Attempt()
@@ -48,7 +48,7 @@
                            "instance_actions", "sce_vnffgs", "sce_rsps", "sce_rsp_hops",
                            "sce_classifiers", "sce_classifier_matches", "instance_sfis", "instance_sfs",
                            "instance_classifications", "instance_sfps", "wims", "wim_accounts", "wim_nfvo_tenants",
-                           "wim_port_mappings", "vim_wim_actions",
+                           "wim_port_mappings", "vim_wim_actions", "instance_interfaces",
                            "instance_wim_nets"]
 
 
@@ -77,7 +77,7 @@
         #print "Adding new vms to the NFVO database"
         #For each vm, we must create the appropriate vm in the NFVO database.
         vmDict = {}
-        for _,vm in VNFCDict.iteritems():
+        for _,vm in VNFCDict.items():
             #This code could make the name of the vms grow and grow.
             #If we agree to follow this convention, we should check with a regex that the vnfc name is not including yet the vnf name
             #vm['name'] = "%s-%s" % (vnf_name,vm['name'])
@@ -222,7 +222,7 @@
         #print "Adding new vms to the NFVO database"
         #For each vm, we must create the appropriate vm in the NFVO database.
         vmDict = {}
-        for _,vm in VNFCDict.iteritems():
+        for _,vm in VNFCDict.items():
             #This code could make the name of the vms grow and grow.
             #If we agree to follow this convention, we should check with a regex that the vnfc name is not including yet the vnf name
             #vm['name'] = "%s-%s" % (vnf_name,vm['name'])
@@ -561,7 +561,7 @@
             raise db_base.db_base_Exception("More than one scenario found with this criteria " + where_text, httperrors.Bad_Request)
         scenario_dict = rows[0]
         if scenario_dict["cloud_config"]:
-            scenario_dict["cloud-config"] = yaml.load(scenario_dict["cloud_config"])
+            scenario_dict["cloud-config"] = yaml.load(scenario_dict["cloud_config"], Loader=yaml.Loader)
         del scenario_dict["cloud_config"]
         # sce_vnfs
         cmd = "SELECT uuid,name,member_vnf_index,vnf_id,description FROM sce_vnfs WHERE scenario_id='{}' "\
@@ -576,7 +576,7 @@
             self.cur.execute(cmd)
             mgmt_access_dict = self.cur.fetchall()
             if mgmt_access_dict[0].get('mgmt_access'):
-                vnf['mgmt_access'] = yaml.load(mgmt_access_dict[0]['mgmt_access'])
+                vnf['mgmt_access'] = yaml.load(mgmt_access_dict[0]['mgmt_access'], Loader=yaml.Loader)
             else:
                 vnf['mgmt_access'] = None
             # sce_interfaces
@@ -824,7 +824,7 @@
                 net["vim_id_sites"]["datacenter_site_id"] = {datacenter_site_id: net['vim_id']}
             sce_net_id = net.get("uuid")
 
-            for datacenter_site_id,vim_id in net["vim_id_sites"].iteritems():
+            for datacenter_site_id,vim_id in net["vim_id_sites"].items():
                 INSERT_={'vim_net_id': vim_id, 'created': net.get('created', False), 'instance_scenario_id':instance_uuid } #,  'type': net['type']
                 INSERT_['datacenter_id'] = datacenter_site_id
                 INSERT_['datacenter_tenant_id'] = scenarioDict["datacenter2tenant"][datacenter_site_id]
@@ -939,7 +939,7 @@
                                             httperrors.Bad_Request)
         instance_dict = rows[0]
         if instance_dict["cloud_config"]:
-            instance_dict["cloud-config"] = yaml.load(instance_dict["cloud_config"])
+            instance_dict["cloud-config"] = yaml.load(instance_dict["cloud_config"], Loader=yaml.Loader)
         del instance_dict["cloud_config"]
 
         # instance_vnfs
@@ -957,7 +957,7 @@
             vnf_mgmt_access_iface = None
             vnf_mgmt_access_vm = None
             if vnf["mgmt_access"]:
-                vnf_mgmt_access = yaml.load(vnf["mgmt_access"])
+                vnf_mgmt_access = yaml.load(vnf["mgmt_access"], Loader=yaml.Loader)
                 vnf_mgmt_access_iface = vnf_mgmt_access.get("interface_id")
                 vnf_mgmt_access_vm = vnf_mgmt_access.get("vm_id")
                 vnf["ip_address"] = vnf_mgmt_access.get("ip-address")
@@ -976,7 +976,7 @@
                 cmd = "SELECT vim_interface_id, instance_net_id, internal_name,external_name, mac_address,"\
                         " ii.ip_address as ip_address, vim_info, i.type as type, sdn_port_id, i.uuid"\
                         " FROM instance_interfaces as ii join interfaces as i on ii.interface_id=i.uuid"\
-                        " WHERE instance_vm_id='{}' ORDER BY created_at".format(vm['uuid'])
+                        " WHERE instance_vm_id='{}' ORDER BY i.created_at".format(vm['uuid'])
                 self.logger.debug(cmd)
                 self.cur.execute(cmd )
                 vm['interfaces'] = self.cur.fetchall()
@@ -1010,6 +1010,13 @@
         self.cur.execute(cmd)
         instance_dict['nets'] = self.cur.fetchall()
 
+        # instance sdn_nets:
+        cmd = "SELECT * FROM instance_wim_nets WHERE instance_scenario_id='{}' ORDER BY created_at;".format(
+            instance_dict['uuid'])
+        self.logger.debug(cmd)
+        self.cur.execute(cmd)
+        instance_dict['sdn_nets'] = self.cur.fetchall()
+
         #instance_sfps
         cmd = "SELECT uuid,vim_sfp_id,sce_rsp_id,datacenter_id,"\
                 "datacenter_tenant_id,status,error_msg,vim_info, related"\
diff --git a/osm_ro/openmano_schemas.py b/RO/osm_ro/openmano_schemas.py
similarity index 100%
rename from osm_ro/openmano_schemas.py
rename to RO/osm_ro/openmano_schemas.py
diff --git a/osm_ro/openmanoclient.py b/RO/osm_ro/openmanoclient.py
similarity index 99%
rename from osm_ro/openmanoclient.py
rename to RO/osm_ro/openmanoclient.py
index e15824a..fc8bde1 100644
--- a/osm_ro/openmanoclient.py
+++ b/RO/osm_ro/openmanoclient.py
@@ -37,10 +37,7 @@
 __version__ = "0.1.0-r470"
 version_date = "Oct 2017"
 
-if sys.version_info.major == 3:
-    from urllib.parse import quote
-elif sys.version_info.major == 2:
-    from urllib import quote
+from urllib.parse import quote
 
 class OpenmanoException(Exception):
     '''Common Exception for all openmano client exceptions'''
@@ -96,7 +93,7 @@
         elif index=='endpoint_url':
             return self.endpoint_url
         else:
-            raise KeyError("Invalid key '%s'" %str(index))
+            raise KeyError("Invalid key '{}'".format(index))
         
     def __setitem__(self,index, value):
         if index=='tenant_name':
@@ -114,7 +111,7 @@
         elif index=='endpoint_url':
             self.endpoint_url = value
         else:
-            raise KeyError("Invalid key '%s'" %str(index)) 
+            raise KeyError("Invalid key '{}'".format(index))
         self.tenant = None # force to reload tenant with different credentials
         self.datacenter = None # force to reload datacenter with different credentials
     
@@ -124,7 +121,7 @@
             raise  OpenmanoBadParamsException("'descriptor_format' must be a 'json' or 'yaml' text")
         if descriptor_format != "json":
             try:
-                return yaml.load(descriptor)
+                return yaml.load(descriptor, Loader=yaml.SafeLoader)
             except yaml.YAMLError as exc:
                 error_pos = ""
                 if hasattr(exc, 'problem_mark'):
@@ -144,7 +141,7 @@
     
     def _parse_yaml(self, descriptor, response=False):
         try:
-            return yaml.load(descriptor)
+            return yaml.load(descriptor, Loader=yaml.SafeLoader)
         except yaml.YAMLError as exc:
             error_pos = ""
             if hasattr(exc, 'problem_mark'):
diff --git a/osm_ro/openmanod.cfg b/RO/osm_ro/openmanod.cfg
similarity index 100%
rename from osm_ro/openmanod.cfg
rename to RO/osm_ro/openmanod.cfg
diff --git a/openmanod b/RO/osm_ro/openmanod.py
similarity index 97%
rename from openmanod
rename to RO/osm_ro/openmanod.py
index ecd9972..637b1da 100755
--- a/openmanod
+++ b/RO/osm_ro/openmanod.py
@@ -53,9 +53,9 @@
 
 __author__ = "Alfonso Tierno, Gerardo Garcia, Pablo Montes"
 __date__ = "$26-aug-2014 11:09:29$"
-__version__ = "6.0.2.post2"
-version_date = "Sep 2019"
-database_version = 39      # expected database schema version
+__version__ = "6.0.4.post6"
+version_date = "Oct 2019"
+database_version = 40      # expected database schema version
 
 global global_config
 global logger
@@ -81,7 +81,7 @@
         with open(configuration_file, 'r') as f:
             config_str = f.read()
         # Parse configuration file
-        config = yaml.load(config_str)
+        config = yaml.load(config_str, Loader=yaml.SafeLoader)
         # Validate configuration file with the config_schema
         js_v(config, config_schema)
 
@@ -191,7 +191,7 @@
                                     "log-socket-host=", "log-socket-port=", "log-file=", "create-tenant="])
         port = None
         port_admin = None
-        config_file = 'osm_ro/openmanod.cfg'
+        config_file = 'openmanod.cfg'
         vnf_repository = None
         log_file = None
         log_socket_host = None
@@ -327,7 +327,7 @@
 
         # WIM module
         wim_persistence = WimPersistence(mydb)
-        wim_engine = WimEngine(wim_persistence)
+        wim_engine = WimEngine(wim_persistence, nfvo.plugins)
         # ---
         nfvo.start_service(mydb, wim_persistence, wim_engine)
 
diff --git a/RO/osm_ro/osm-ro.service b/RO/osm_ro/osm-ro.service
new file mode 100644
index 0000000..4f4e4ca
--- /dev/null
+++ b/RO/osm_ro/osm-ro.service
@@ -0,0 +1,26 @@
+##
+# Copyright 2015 Telefonica Investigacion y Desarrollo, S.A.U.
+# 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.
+##
+
+[Unit]
+Description=openmano server (OSM RO)
+After=mysql.service
+
+[Service]
+ExecStart=/usr/bin/openmanod -c /etc/osm/openmanod.cfg --log-file=/var/log/osm/openmano.log
+Restart=always
+
+[Install]
+WantedBy=multi-user.target
+
diff --git a/scripts/RO-of b/RO/osm_ro/scripts/RO-of
similarity index 100%
rename from scripts/RO-of
rename to RO/osm_ro/scripts/RO-of
diff --git a/scripts/RO-start.sh b/RO/osm_ro/scripts/RO-start.sh
similarity index 67%
rename from scripts/RO-start.sh
rename to RO/osm_ro/scripts/RO-start.sh
index 47547cd..94183e9 100755
--- a/scripts/RO-start.sh
+++ b/RO/osm_ro/scripts/RO-start.sh
@@ -1,4 +1,18 @@
 #!/bin/bash
+##
+# Copyright 2015 Telefonica Investigacion y Desarrollo, S.A.U.
+# 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.
+##
 
 # This script is intended for launching RO from a docker container.
 # It waits for mysql server ready, normally running on a separate container, ...
@@ -92,7 +106,7 @@
 
 
 echo "3/4 Init database"
-RO_PATH=`python -c 'import osm_ro; print(osm_ro.__path__[0])'`
+RO_PATH=`python3 -c 'import osm_ro; print(osm_ro.__path__[0])'`
 echo "RO_PATH: $RO_PATH"
 if ! is_db_created "$RO_DB_HOST" "$RO_DB_PORT" "$RO_DB_USER" "$RO_DB_PASSWORD" "$RO_DB_NAME" "27"
 then
@@ -111,34 +125,35 @@
         -P "$RO_DB_PORT" -d "$RO_DB_NAME" -b /var/log/osm
 fi
 
-OVIM_PATH=`python -c 'import lib_osm_openvim; print(lib_osm_openvim.__path__[0])'`
-echo "OVIM_PATH: $OVIM_PATH"
-if ! is_db_created "$RO_DB_OVIM_HOST" "$RO_DB_OVIM_PORT" "$RO_DB_OVIM_USER" "$RO_DB_OVIM_PASSWORD" "$RO_DB_OVIM_NAME" \
-    "22"
-then
-    if [ -n "$RO_DB_OVIM_ROOT_PASSWORD" ] ; then
-        mysqladmin -h"$RO_DB_OVIM_HOST" -uroot -p"$RO_DB_OVIM_ROOT_PASSWORD" create "$RO_DB_OVIM_NAME"
-        echo "CREATE USER '${RO_DB_OVIM_USER}'@'%' IDENTIFIED BY '${RO_DB_OVIM_PASSWORD}';" |
-            mysql -h"$RO_DB_OVIM_HOST" -uroot -p"$RO_DB_OVIM_ROOT_PASSWORD" ||
-            echo "user ${RO_DB_OVIM_USER} already created?"
-        echo "GRANT ALL PRIVILEGES ON ${RO_DB_OVIM_NAME}.* TO '${RO_DB_OVIM_USER}'@'%';" |
-            mysql -h"$RO_DB_OVIM_HOST" -uroot -p"$RO_DB_OVIM_ROOT_PASSWORD"  ||
-            echo "user ${RO_DB_OVIM_USER} already granted?"
-    fi
-    ${OVIM_PATH}/database_utils/init_vim_db.sh  -u "$RO_DB_OVIM_USER" -p "$RO_DB_OVIM_PASSWORD" -h "$RO_DB_OVIM_HOST" \
-        -P "${RO_DB_OVIM_PORT}" -d "${RO_DB_OVIM_NAME}" || exit 1
-else
-    echo "  migrate database version"
-    ${OVIM_PATH}/database_utils/migrate_vim_db.sh -u "$RO_DB_OVIM_USER" -p "$RO_DB_OVIM_PASSWORD" -h "$RO_DB_OVIM_HOST"\
-        -P "$RO_DB_OVIM_PORT" -d "$RO_DB_OVIM_NAME" -b /var/log/osm
-fi
-
+# TODO py3 BEGIN
+#OVIM_PATH=`python3 -c 'import lib_osm_openvim; print(lib_osm_openvim.__path__[0])'`
+#echo "OVIM_PATH: $OVIM_PATH"
+#if ! is_db_created "$RO_DB_OVIM_HOST" "$RO_DB_OVIM_PORT" "$RO_DB_OVIM_USER" "$RO_DB_OVIM_PASSWORD" "$RO_DB_OVIM_NAME" \
+#    "22"
+#then
+#    if [ -n "$RO_DB_OVIM_ROOT_PASSWORD" ] ; then
+#        mysqladmin -h"$RO_DB_OVIM_HOST" -uroot -p"$RO_DB_OVIM_ROOT_PASSWORD" create "$RO_DB_OVIM_NAME"
+#        echo "CREATE USER '${RO_DB_OVIM_USER}'@'%' IDENTIFIED BY '${RO_DB_OVIM_PASSWORD}';" |
+#            mysql -h"$RO_DB_OVIM_HOST" -uroot -p"$RO_DB_OVIM_ROOT_PASSWORD" ||
+#            echo "user ${RO_DB_OVIM_USER} already created?"
+#        echo "GRANT ALL PRIVILEGES ON ${RO_DB_OVIM_NAME}.* TO '${RO_DB_OVIM_USER}'@'%';" |
+#            mysql -h"$RO_DB_OVIM_HOST" -uroot -p"$RO_DB_OVIM_ROOT_PASSWORD"  ||
+#            echo "user ${RO_DB_OVIM_USER} already granted?"
+#    fi
+#    ${OVIM_PATH}/database_utils/init_vim_db.sh  -u "$RO_DB_OVIM_USER" -p "$RO_DB_OVIM_PASSWORD" -h "$RO_DB_OVIM_HOST" \
+#        -P "${RO_DB_OVIM_PORT}" -d "${RO_DB_OVIM_NAME}" || exit 1
+#else
+#    echo "  migrate database version"
+#    ${OVIM_PATH}/database_utils/migrate_vim_db.sh -u "$RO_DB_OVIM_USER" -p "$RO_DB_OVIM_PASSWORD" -h "$RO_DB_OVIM_HOST"\
+#        -P "$RO_DB_OVIM_PORT" -d "$RO_DB_OVIM_NAME" -b /var/log/osm
+#fi
+# TODO py3 END
 
 echo "4/4 Try to start"
 # look for openmanod.cfg
 RO_CONFIG_FILE="/etc/osm/openmanod.cfg"
-[ -f "$RO_CONFIG_FILE" ] || RO_CONFIG_FILE=$(python -c 'import osm_ro; print(osm_ro.__path__[0])')/openmanod.cfg
+[ -f "$RO_CONFIG_FILE" ] || RO_CONFIG_FILE=$(python3 -c 'import osm_ro; print(osm_ro.__path__[0])')/openmanod.cfg
 [ -f "$RO_CONFIG_FILE" ] || ! echo "configuration file 'openmanod.cfg' not found" || exit 1
 
-openmanod -c "$RO_CONFIG_FILE"  --create-tenant=osm  # --log-file=/var/log/osm/openmano.log
+python3 -m osm_ro.openmanod -c "$RO_CONFIG_FILE"  --create-tenant=osm  # --log-file=/var/log/osm/openmano.log
 
diff --git a/scripts/get-options.sh b/RO/osm_ro/scripts/get-options.sh
similarity index 100%
rename from scripts/get-options.sh
rename to RO/osm_ro/scripts/get-options.sh
diff --git a/scripts/install-lib-osm-openvim.sh b/RO/osm_ro/scripts/install-lib-osm-openvim.sh
similarity index 97%
rename from scripts/install-lib-osm-openvim.sh
rename to RO/osm_ro/scripts/install-lib-osm-openvim.sh
index c1374d5..93df95e 100755
--- a/scripts/install-lib-osm-openvim.sh
+++ b/RO/osm_ro/scripts/install-lib-osm-openvim.sh
@@ -21,6 +21,8 @@
 
 # author: Alfonso Tierno
 
+exit 0 # TODO py3   for the moment no openvim library is installed
+
 # It uses following env, if not provided filling by default
 [ -z "$GIT_OVIM_URL" ] && GIT_OVIM_URL=https://osm.etsi.org/gerrit/osm/openvim.git
 [ -z "$DEVELOP" ] && DEVELOP=""
diff --git a/scripts/install-openmano-service.sh b/RO/osm_ro/scripts/install-openmano-service.sh
similarity index 100%
rename from scripts/install-openmano-service.sh
rename to RO/osm_ro/scripts/install-openmano-service.sh
diff --git a/scripts/install-openmano.sh b/RO/osm_ro/scripts/install-openmano.sh
similarity index 100%
rename from scripts/install-openmano.sh
rename to RO/osm_ro/scripts/install-openmano.sh
diff --git a/scripts/install-osm-im.sh b/RO/osm_ro/scripts/install-osm-im.sh
similarity index 92%
rename from scripts/install-osm-im.sh
rename to RO/osm_ro/scripts/install-osm-im.sh
index 2fad214..8f733ce 100755
--- a/scripts/install-osm-im.sh
+++ b/RO/osm_ro/scripts/install-osm-im.sh
@@ -25,7 +25,7 @@
 [ -z "$GIT_OSMIM_URL" ] && GIT_OSMIM_URL=https://osm.etsi.org/gerrit/osm/IM.git
 [ -z "$DEVELOP" ] && DEVELOP=""
 # folder where RO is installed
-[ -z "$BASEFOLDER" ] && HERE=$(dirname $(readlink -f ${BASH_SOURCE[0]})) && BASEFOLDER=$(dirname $HERE)
+[ -z "$BASEFOLDER" ] && HERE=$(dirname $(readlink -f ${BASH_SOURCE[0]})) && BASEFOLDER=$(dirname $(dirname $HERE))
 [ -z "$SUDO_USER" ] && SUDO_USER="$USER"
 [ -z "$NO_PACKAGES" ] && NO_PACKAGES=""
 [ -z "$_DISTRO" ] && _DISTRO="Ubuntu"
@@ -96,10 +96,10 @@
     # apt-get update
     # apt-get install -y git python-pip
     # pip2 install pip==9.0.3
-    pip2 install pyangbind || exit 1
+    python3 -m pip install pyangbind || exit 1
 fi
 
-PYBINDPLUGIN=$(python2 -c 'import pyangbind; import os; print "%s/plugin" % os.path.dirname(pyangbind.__file__)')
+PYBINDPLUGIN=$(python3 -c 'import pyangbind; import os; print(os.path.dirname(pyangbind.__file__)+"/plugin")')
 su $SUDO_USER -c 'mkdir -p "'${BASEFOLDER}/IM/osm_im'"'
 su $SUDO_USER -c 'touch "'${BASEFOLDER}/IM/osm_im/__init__.py'"'
 # wget -q https://raw.githubusercontent.com/RIFTIO/RIFT.ware/RIFT.ware-4.4.1/modules/core/util/yangtools/yang/rw-pb-ext.yang -O "${BASEFOLDER}/IM/models/yang/rw-pb-ext.yang"
@@ -108,4 +108,4 @@
         -o "${BASEFOLDER}/IM/osm_im/${target}.py" "${BASEFOLDER}/IM/models/yang/${target}.yang"
 done
 
-pip2 install -e "${BASEFOLDER}/IM" || ! echo "ERROR installing python-osm-im library!!!" >&2  || exit 1
+python3 -m pip install -e "${BASEFOLDER}/IM" || ! echo "ERROR installing python-osm-im library!!!" >&2  || exit 1
diff --git a/scripts/openmano-report b/RO/osm_ro/scripts/openmano-report
similarity index 100%
rename from scripts/openmano-report
rename to RO/osm_ro/scripts/openmano-report
diff --git a/scripts/service-openmano b/RO/osm_ro/scripts/service-openmano
similarity index 100%
rename from scripts/service-openmano
rename to RO/osm_ro/scripts/service-openmano
diff --git a/RO/osm_ro/sdn.py b/RO/osm_ro/sdn.py
new file mode 100755
index 0000000..91cc9b2
--- /dev/null
+++ b/RO/osm_ro/sdn.py
@@ -0,0 +1,329 @@
+# -*- coding: utf-8 -*-
+
+##
+# Copyright 2019 Telefonica Investigacion y Desarrollo, S.A.U.
+# All Rights Reserved.
+#
+# 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.
+##
+
+"""
+This is the thread for the http server North API. 
+Two thread will be launched, with normal and administrative permissions.
+"""
+import yaml
+from uuid import uuid4
+from http import HTTPStatus
+
+__author__ = "Alfonso Tierno"
+__date__ = "2019-10-22"
+__version__ = "0.1"
+version_date = "Oct 2019"
+
+
+class SdnException(Exception):
+    def __init__(self, message, http_code=HTTPStatus.BAD_REQUEST.value):
+        self.http_code = http_code
+        Exception.__init__(self, message)
+
+
+class Sdn():
+    running_info = {}  # TODO OVIM move the info of running threads from config_dic to this static variable
+    of_module = {}
+
+    def __init__(self, db, plugins):
+        self.db = db
+        self.plugins = plugins
+
+    def start_service(self):
+        pass  # TODO py3 needed to load wims and plugins
+
+    def stop_service(self):
+        pass  # nothing needed
+
+    def show_network(self, uuid):
+        pass
+
+    def delete_network(self, uuid):
+        pass
+
+    def new_network(self, network):
+        pass
+
+    def get_openflow_rules(self, network_id=None):
+        """
+        Get openflow id from DB
+        :param network_id: Network id, if none all networks will be retrieved
+        :return: Return a list with Openflow rules per net
+        """
+        # ignore input data
+        if not network_id:
+
+            where_ = {}
+        else:
+            where_ = {"net_id": network_id}
+        result, content = self.db.get_table(
+            SELECT=("name", "net_id", "ofc_id", "priority", "vlan_id", "ingress_port", "src_mac", "dst_mac", "actions"),
+            WHERE=where_, FROM='of_flows')
+
+        if result < 0:
+            raise SdnException(str(content), -result)
+        return content
+
+    def edit_openflow_rules(self, network_id=None):
+
+        """
+        To make actions over the net. The action is to reinstall the openflow rules
+        network_id can be 'all'
+        :param network_id: Network id, if none all networks will be retrieved
+        :return : Number of nets updated
+        """
+
+        # ignore input data
+        if not network_id:
+            where_ = {}
+        else:
+            where_ = {"uuid": network_id}
+        result, content = self.db.get_table(SELECT=("uuid", "type"), WHERE=where_, FROM='nets')
+
+        if result < 0:
+            raise SdnException(str(content), -result)
+
+        for net in content:
+            if net["type"] != "ptp" and net["type"] != "data":
+                result -= 1
+                continue
+
+            try:
+                self.net_update_ofc_thread(net['uuid'])
+            except SdnException as e:
+                raise SdnException("Error updating network'{}' {}".format(net['uuid'], e),
+                                   HTTPStatus.INTERNAL_SERVER_ERROR.value)
+            except Exception as e:
+                raise SdnException("Error updating network '{}' {}".format(net['uuid'], e),
+                                   HTTPStatus.INTERNAL_SERVER_ERROR.value)
+
+        return result
+
+    def delete_openflow_rules(self, ofc_id=None):
+        """
+        To make actions over the net. The action is to delete ALL openflow rules
+        :return: return operation result
+        """
+
+        if not ofc_id:
+            if 'Default' in self.config['ofcs_thread']:
+                r, c = self.config['ofcs_thread']['Default'].insert_task("clear-all")
+            else:
+                raise SdnException("Default Openflow controller not not running", HTTPStatus.NOT_FOUND.value)
+
+        elif ofc_id in self.config['ofcs_thread']:
+            r, c = self.config['ofcs_thread'][ofc_id].insert_task("clear-all")
+
+            # ignore input data
+            if r < 0:
+                raise SdnException(str(c), -r)
+        else:
+            raise SdnException("Openflow controller not found with ofc_id={}".format(ofc_id),
+                               HTTPStatus.NOT_FOUND.value)
+        return r
+
+    def get_openflow_ports(self, ofc_id=None):
+        """
+        Obtain switch ports names of openflow controller
+        :return: Return flow ports in DB
+        """
+        if not ofc_id:
+            if 'Default' in self.config['ofcs_thread']:
+                conn = self.config['ofcs_thread']['Default'].OF_connector
+            else:
+                raise SdnException("Default Openflow controller not not running", HTTPStatus.NOT_FOUND.value)
+
+        elif ofc_id in self.config['ofcs_thread']:
+            conn = self.config['ofcs_thread'][ofc_id].OF_connector
+        else:
+            raise SdnException("Openflow controller not found with ofc_id={}".format(ofc_id),
+                               HTTPStatus.NOT_FOUND.value)
+        return conn.pp2ofi
+
+    def new_of_controller(self, ofc_data):
+        """
+        Create a new openflow controller into DB
+        :param ofc_data: Dict openflow controller data
+        :return: openflow controller dpid
+        """
+        db_wim = {
+            "uuid": str(uuid4()),
+            "name": ofc_data["name"],
+            "description": "",
+            "type": ofc_data["type"],
+            "wim_url": "{}:{}".format(ofc_data["ip"], ofc_data["port"]),
+        }
+        db_wim_account = {
+            "uuid": str(uuid4()),
+            "name": ofc_data["name"],
+            "wim_id": db_wim["uuid"],
+            "sdn": "true",
+            "user": ofc_data.get("user"),
+            "password": ofc_data.get("password"),
+            "config": yaml.safe_dump({"dpid": ofc_data["dpid"], "version": ofc_data.get("version")},
+                                     default_flow_style=True, width=256)
+        }
+        db_tables = [
+            {"wims": db_wim},
+            {"wim_accounts": db_wim_account},
+        ]
+        uuid_list = [db_wim["uuid"], db_wim_account["uuid"]]
+        self.db.new_rows(db_tables, uuid_list)
+        return db_wim_account["uuid"]
+
+    def edit_of_controller(self, of_id, ofc_data):
+        """
+        Edit an openflow controller entry from DB
+        :return:
+        """
+        if not ofc_data:
+            raise SdnException("No data received during uptade OF contorller",
+                               http_code=HTTPStatus.INTERNAL_SERVER_ERROR.value)
+
+        old_of_controller = self.show_of_controller(of_id)
+
+        if old_of_controller:
+            result, content = self.db.update_rows('ofcs', ofc_data, WHERE={'uuid': of_id}, log=False)
+            if result >= 0:
+                return ofc_data
+            else:
+                raise SdnException("Error uptating OF contorller with uuid {}".format(of_id),
+                                   http_code=-result)
+        else:
+            raise SdnException("Error uptating OF contorller with uuid {}".format(of_id),
+                               http_code=HTTPStatus.INTERNAL_SERVER_ERROR.value)
+
+    def delete_of_controller(self, of_id):
+        """
+        Delete an openflow controller from DB.
+        :param of_id: openflow controller dpid
+        :return:
+        """
+        wim_accounts = self.db.get_rows(FROM='wim_accounts', WHERE={"uuid": of_id, "sdn": "true"})
+        if not wim_accounts:
+            raise SdnException("Cannot find sdn controller with id='{}'".format(of_id),
+                               http_code=HTTPStatus.NOT_FOUND.value)
+        elif len(wim_accounts) > 1:
+            raise SdnException("Found more than one sdn controller with id='{}'".format(of_id),
+                               http_code=HTTPStatus.CONFLICT.value)
+        self.db.delete_row(FROM='wim_accounts', WHERE={"uuid": of_id})
+        self.db.delete_row(FROM='wims', WHERE={"uuid": wim_accounts[0]["wim_id"]})
+        return of_id
+
+    def _format_of_controller(self, wim_account, wim=None):
+        of_data = {x: wim_account[x] for x in ("uuid", "name", "user")}
+        if isinstance(wim_account["config"], str):
+            config = yaml.load(wim_account["config"], Loader=yaml.Loader)
+        of_data["dpid"] = config.get("dpid")
+        of_data["version"] = config.get("version")
+        if wim:
+            ip, port = wim["wim_url"].split(":")
+            of_data["ip"] = ip
+            of_data["port"] = port
+            of_data["type"] = wim["type"]
+        return of_data
+
+    def show_of_controller(self, of_id):
+        """
+        Show an openflow controller by dpid from DB.
+        :param db_filter: List with where query parameters
+        :return:
+        """
+        wim_accounts = self.db.get_rows(FROM='wim_accounts', WHERE={"uuid": of_id, "sdn": "true"})
+        if not wim_accounts:
+            raise SdnException("Cannot find sdn controller with id='{}'".format(of_id),
+                               http_code=HTTPStatus.NOT_FOUND.value)
+        elif len(wim_accounts) > 1:
+            raise SdnException("Found more than one sdn controller with id='{}'".format(of_id),
+                               http_code=HTTPStatus.CONFLICT.value)
+        wims = self.db.get_rows(FROM='wims', WHERE={"uuid": wim_accounts[0]["wim_id"]})
+        return self._format_of_controller(wim_accounts[0], wims[0])
+
+    def get_of_controllers(self, filter=None):
+        """
+        Show an openflow controllers from DB.
+        :return:
+        """
+        filter = filter or {}
+        filter["sdn"] = "true"
+        wim_accounts = self.db.get_rows(FROM='wim_accounts', WHERE=filter)
+        return [self._format_of_controller(w) for w in wim_accounts]
+
+    def set_of_port_mapping(self, maps, sdn_id, switch_dpid, vim_id):
+        """
+        Create new port mapping entry
+        :param of_maps: List with port mapping information
+        # maps =[{"ofc_id": <ofc_id>,"region": datacenter region,"compute_node": compute uuid,"pci": pci adress,
+                "switch_dpid": swith dpid,"switch_port": port name,"switch_mac": mac}]
+        :param sdn_id: ofc id
+        :param switch_dpid: switch  dpid
+        :param vim_id: datacenter
+        :return:
+        """
+        # get wim from wim_account
+        wim_accounts = self.db.get_rows(FROM='wim_accounts', WHERE={"uuid": sdn_id})
+        if not wim_accounts:
+            raise SdnException("Not found sdn id={}".format(sdn_id), http_code=HTTPStatus.NOT_FOUND.value)
+        wim_id = wim_accounts[0]["wim_id"]
+        db_wim_port_mappings = []
+        for map in maps:
+            new_map = {
+                'wim_id': wim_id,
+                'switch_dpid': switch_dpid,
+                "switch_port": map.get("switch_port"),
+                'datacenter_id': vim_id,
+                "device_id": map.get("compute_node"),
+                "service_endpoint_id": switch_dpid + "-" + str(uuid4())
+            }
+            if map.get("pci"):
+                new_map["device_interface_id"] = map["pci"].lower()
+            config = {}
+            if map.get("switch_mac"):
+                config["switch_mac"] = map["switch_mac"]
+            if config:
+                new_map["service_mapping_info"] = yaml.safe_dump(config, default_flow_style=True, width=256)
+            db_wim_port_mappings.append(new_map)
+
+        db_tables = [
+            {"wim_port_mappings": db_wim_port_mappings},
+        ]
+        self.db.new_rows(db_tables, [])
+        return db_wim_port_mappings
+
+    def clear_of_port_mapping(self, db_filter=None):
+        """
+        Clear port mapping filtering using db_filter dict
+        :param db_filter: Parameter to filter during remove process
+        :return:
+        """
+        return self.db.delete_row(FROM='wim_port_mappings', WHERE=db_filter)
+
+    def get_of_port_mappings(self, db_filter=None):
+        """
+        Retrive port mapping from DB
+        :param db_filter:
+        :return:
+        """
+        maps = self.db.get_rows(WHERE=db_filter, FROM='wim_port_mappings')
+        for map in maps:
+            if map.get("service_mapping_info"):
+                map["service_mapping_info"] = yaml.load(map["service_mapping_info"], Loader=yaml.Loader)
+            else:
+                map["service_mapping_info"] = {}
+        return maps
diff --git a/RO/osm_ro/tests/__init__.py b/RO/osm_ro/tests/__init__.py
new file mode 100644
index 0000000..7284a2b
--- /dev/null
+++ b/RO/osm_ro/tests/__init__.py
@@ -0,0 +1,13 @@
+##
+# 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.
+##
diff --git a/osm_ro/tests/db_helpers.py b/RO/osm_ro/tests/db_helpers.py
similarity index 100%
rename from osm_ro/tests/db_helpers.py
rename to RO/osm_ro/tests/db_helpers.py
diff --git a/osm_ro/tests/helpers.py b/RO/osm_ro/tests/helpers.py
similarity index 97%
rename from osm_ro/tests/helpers.py
rename to RO/osm_ro/tests/helpers.py
index 787fbce..011e880 100644
--- a/osm_ro/tests/helpers.py
+++ b/RO/osm_ro/tests/helpers.py
@@ -36,9 +36,9 @@
 import unittest
 from collections import defaultdict
 
-from six import StringIO
+from io import StringIO
 
-from mock import MagicMock, patch
+from unittest.mock import MagicMock, patch
 
 logger = logging.getLogger()
 
diff --git a/osm_ro/tests/test_db.py b/RO/osm_ro/tests/test_db.py
similarity index 87%
rename from osm_ro/tests/test_db.py
rename to RO/osm_ro/tests/test_db.py
index e152347..e381116 100644
--- a/osm_ro/tests/test_db.py
+++ b/RO/osm_ro/tests/test_db.py
@@ -1,10 +1,22 @@
 # -*- coding: utf-8 -*-
+##
+# 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.
+##
+
 # pylint: disable=E1101
 import unittest
 
 from MySQLdb import connect, cursors, DatabaseError, IntegrityError
-import mock
-from mock import Mock
 
 from ..db_base import retry, with_transaction
 from ..nfvo_db import nfvo_db
diff --git a/osm_ro/tests/test_utils.py b/RO/osm_ro/tests/test_utils.py
similarity index 79%
rename from osm_ro/tests/test_utils.py
rename to RO/osm_ro/tests/test_utils.py
index 9fd71cf..c62c954 100644
--- a/osm_ro/tests/test_utils.py
+++ b/RO/osm_ro/tests/test_utils.py
@@ -1,4 +1,18 @@
 # -*- coding: utf-8 -*-
+##
+# 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.
+##
+
 # pylint: disable=E1101
 
 import unittest
diff --git a/osm_ro/utils.py b/RO/osm_ro/utils.py
similarity index 87%
rename from osm_ro/utils.py
rename to RO/osm_ro/utils.py
index 625ff6d..ac291c1 100644
--- a/osm_ro/utils.py
+++ b/RO/osm_ro/utils.py
@@ -35,16 +35,12 @@
 from functools import reduce, partial, wraps
 from itertools import tee
 
-import six
-from six.moves import filter, filterfalse
+from itertools import filterfalse
 
 from jsonschema import exceptions as js_e
 from jsonschema import validate as js_v
 
-if six.PY3:
-    from inspect import getfullargspec as getspec
-else:
-    from inspect import getargspec as getspec
+from inspect import getfullargspec as getspec
 
 #from bs4 import BeautifulSoup
 
@@ -77,28 +73,31 @@
         #print "Input data: ", str(client_data)
         return True, client_data
     except js_e.ValidationError as exc:
-        print "validate_in error, jsonschema exception ", exc.message, "at", exc.path
+        print("validate_in error, jsonschema exception ", exc.message, "at", exc.path)
         return False, ("validate_in error, jsonschema exception ", exc.message, "at", exc.path)
 
 def remove_extra_items(data, schema):
     deleted = []
-    if type(data) is tuple or type(data) is list:
+    if isinstance(data, (tuple, list)):
         for d in data:
             a = remove_extra_items(d, schema['items'])
-            if a is not None:
+            if a:
                 deleted.append(a)
-    elif type(data) is dict:
+    elif isinstance(data, dict):
         # TODO deal with patternProperties
         if 'properties' not in schema:
             return None
+        to_delete = []
         for k in data.keys():
-            if k in schema['properties'].keys():
+            if k in schema['properties']:
                 a = remove_extra_items(data[k], schema['properties'][k])
-                if a is not None:
+                if a:
                     deleted.append({k: a})
             elif not schema.get('additionalProperties'):
-                del data[k]
+                to_delete.append(k)
                 deleted.append(k)
+        for k in to_delete:
+            del data[k]
     if len(deleted) == 0:
         return None
     elif len(deleted) == 1:
@@ -113,16 +112,24 @@
 
 
 def delete_nulls(var):
-    if type(var) is dict:
+    if isinstance(var, dict):
+        to_delete = []
         for k in var.keys():
-            if var[k] is None: del var[k]
-            elif type(var[k]) is dict or type(var[k]) is list or type(var[k]) is tuple:
-                if delete_nulls(var[k]): del var[k]
-        if len(var) == 0: return True
-    elif type(var) is list or type(var) is tuple:
+            if var[k] is None:
+                to_delete.append([k])
+            elif isinstance(var[k], (dict, list, tuple)):
+                if delete_nulls(var[k]):
+                    to_delete.append(k)
+        for k in to_delete:
+            del var[k]
+        if len(var) == 0:
+            return True
+    elif isinstance(var, (list, tuple)):
         for k in var:
-            if type(k) is dict: delete_nulls(k)
-        if len(var) == 0: return True
+            if isinstance(k, dict):
+                delete_nulls(k)
+        if len(var) == 0:
+            return True
     return False
 
 
@@ -135,9 +142,9 @@
     Return:
         None
     '''
-    if type(data) is dict:
+    if isinstance(data, dict):
         for k in data.keys():
-            if type(data[k]) is dict or type(data[k]) is tuple or type(data[k]) is list:
+            if isinstance(data[k], (dict, tuple, list)):
                 convert_bandwidth(data[k], reverse)
         if "bandwidth" in data:
             try:
@@ -145,19 +152,24 @@
                 if not reverse:
                     pos = value.find("bps")
                     if pos>0:
-                        if value[pos-1]=="G": data["bandwidth"] =  int(data["bandwidth"][:pos-1]) * 1000
-                        elif value[pos-1]=="k": data["bandwidth"]= int(data["bandwidth"][:pos-1]) / 1000
-                        else: data["bandwidth"]= int(data["bandwidth"][:pos-1])
+                        if value[pos-1]=="G":
+                            data["bandwidth"] = int(data["bandwidth"][:pos-1]) * 1000
+                        elif value[pos-1]=="k":
+                            data["bandwidth"]= int(data["bandwidth"][:pos-1]) // 1000
+                        else:
+                            data["bandwidth"]= int(data["bandwidth"][:pos])
                 else:
                     value = int(data["bandwidth"])
-                    if value % 1000 == 0: data["bandwidth"]=str(value/1000) + " Gbps"
-                    else: data["bandwidth"]=str(value) + " Mbps"
+                    if value % 1000 == 0 and value > 1000:
+                        data["bandwidth"] = str(value // 1000) + " Gbps"
+                    else:
+                        data["bandwidth"] = str(value) + " Mbps"
             except:
-                print "convert_bandwidth exception for type", type(data["bandwidth"]), " data", data["bandwidth"]
+                print("convert_bandwidth exception for type", type(data["bandwidth"]), " data", data["bandwidth"])
                 return
-    if type(data) is tuple or type(data) is list:
+    if isinstance(data, (tuple, list)):
         for k in data:
-            if type(k) is dict or type(k) is tuple or type(k) is list:
+            if isinstance(k, (dict, tuple, list)):
                 convert_bandwidth(k, reverse)
 
 def convert_float_timestamp2str(var):
diff --git a/osm_ro/vim_thread.py b/RO/osm_ro/vim_thread.py
similarity index 71%
rename from osm_ro/vim_thread.py
rename to RO/osm_ro/vim_thread.py
index 733dfc2..8d397c2 100644
--- a/osm_ro/vim_thread.py
+++ b/RO/osm_ro/vim_thread.py
@@ -78,34 +78,18 @@
 
 import threading
 import time
-import Queue
+import queue
 import logging
-import vimconn
-import vimconn_openvim
-import vimconn_aws
-import vimconn_opennebula
-import vimconn_openstack
-import vimconn_vmware
-import vimconn_fos
-import vimconn_azure
+from osm_ro import vimconn
+from osm_ro.wim.sdnconn import SdnConnectorError
 import yaml
-from db_base import db_base_Exception
-from lib_osm_openvim.ovim import ovimException
+from osm_ro.db_base import db_base_Exception
+from http import HTTPStatus
 from copy import deepcopy
 
 __author__ = "Alfonso Tierno, Pablo Montes"
 __date__ = "$28-Sep-2017 12:07:15$"
 
-vim_module = {
-    "openvim": vimconn_openvim,
-    "aws": vimconn_aws,
-    "opennebula": vimconn_opennebula,
-    "openstack": vimconn_openstack,
-    "vmware": vimconn_vmware,
-    "fos": vimconn_fos,
-    "azure": vimconn_azure,
-}
-
 
 def is_task_id(task_id):
     return task_id.startswith("TASK-")
@@ -125,8 +109,7 @@
     REFRESH_ERROR = 600
     REFRESH_DELETE = 3600 * 10
 
-    def __init__(self, task_lock, name=None, datacenter_name=None, datacenter_tenant_id=None,
-                 db=None, db_lock=None, ovim=None):
+    def __init__(self, task_lock, plugins, name=None, wim_account_id=None, datacenter_tenant_id=None, db=None):
         """Init a thread.
         Arguments:
             'id' number of thead
@@ -135,60 +118,115 @@
             'db', 'db_lock': database class and lock to use it in exclusion
         """
         threading.Thread.__init__(self)
+        self.plugins = plugins
+        self.plugin_name = "unknown"
         self.vim = None
+        self.sdnconnector = None
+        self.sdnconn_config = None
         self.error_status = None
-        self.datacenter_name = datacenter_name
+        self.wim_account_id = wim_account_id
         self.datacenter_tenant_id = datacenter_tenant_id
-        self.ovim = ovim
+        self.port_mapping = None
+        if self.wim_account_id:
+            self.target_k = "wim_account_id"
+            self.target_v = self.wim_account_id
+        else:
+            self.target_k = "datacenter_vim_id"
+            self.target_v = self.datacenter_tenant_id
         if not name:
-            self.name = vimconn["id"] + "." + vimconn["config"]["datacenter_tenant_id"]
+            self.name = wim_account_id or str(datacenter_tenant_id)
         else:
             self.name = name
         self.vim_persistent_info = {}
         self.my_id = self.name[:64]
 
-        self.logger = logging.getLogger('openmano.vim.' + self.name)
+        self.logger = logging.getLogger('openmano.{}.{}'.format("vim" if self.datacenter_tenant_id else "sdn",
+                                                                self.name))
         self.db = db
-        self.db_lock = db_lock
 
         self.task_lock = task_lock
-        self.task_queue = Queue.Queue(2000)
+        self.task_queue = queue.Queue(2000)
 
-    def get_vimconnector(self):
-        try:
-            from_ = "datacenter_tenants as dt join datacenters as d on dt.datacenter_id=d.uuid"
-            select_ = ('type', 'd.config as config', 'd.uuid as datacenter_id', 'vim_url', 'vim_url_admin',
-                       'd.name as datacenter_name', 'dt.uuid as datacenter_tenant_id',
-                       'dt.vim_tenant_name as vim_tenant_name', 'dt.vim_tenant_id as vim_tenant_id',
-                       'user', 'passwd', 'dt.config as dt_config')
-            where_ = {"dt.uuid": self.datacenter_tenant_id}
-            vims = self.db.get_rows(FROM=from_, SELECT=select_, WHERE=where_)
-            vim = vims[0]
-            vim_config = {}
-            if vim["config"]:
-                vim_config.update(yaml.load(vim["config"]))
-            if vim["dt_config"]:
-                vim_config.update(yaml.load(vim["dt_config"]))
-            vim_config['datacenter_tenant_id'] = vim.get('datacenter_tenant_id')
-            vim_config['datacenter_id'] = vim.get('datacenter_id')
+    def _proccess_sdn_exception(self, exc):
+        if isinstance(exc, SdnConnectorError):
+            raise
+        else:
+            self.logger.error("plugin={} throws a non SdnConnectorError exception {}".format(self.plugin_name, exc),
+                              exc_info=True)
+            raise SdnConnectorError(str(exc), http_code=HTTPStatus.INTERNAL_SERVER_ERROR.value) from exc
 
-            # get port_mapping
-            with self.db_lock:
-                vim_config["wim_external_ports"] = self.ovim.get_of_port_mappings(
-                    db_filter={"region": vim_config['datacenter_id'], "pci": None})
+    def _proccess_vim_exception(self, exc):
+        if isinstance(exc, vimconn.vimconnException):
+            raise
+        else:
+            self.logger.error("plugin={} throws a non vimconnException exception {}".format(self.plugin_name, exc),
+                              exc_info=True)
+            raise vimconn.vimconnException(str(exc), http_code=HTTPStatus.INTERNAL_SERVER_ERROR.value) from exc
 
-            self.vim = vim_module[vim["type"]].vimconnector(
-                uuid=vim['datacenter_id'], name=vim['datacenter_name'],
-                tenant_id=vim['vim_tenant_id'], tenant_name=vim['vim_tenant_name'],
-                url=vim['vim_url'], url_admin=vim['vim_url_admin'],
-                user=vim['user'], passwd=vim['passwd'],
-                config=vim_config, persistent_info=self.vim_persistent_info
-            )
-            self.error_status = None
-        except Exception as e:
-            self.logger.error("Cannot load vimconnector for vim_account {}: {}".format(self.datacenter_tenant_id, e))
-            self.vim = None
-            self.error_status = "Error loading vimconnector: {}".format(e)
+    def get_vim_sdn_connector(self):
+        if self.datacenter_tenant_id:
+            try:
+                from_ = "datacenter_tenants as dt join datacenters as d on dt.datacenter_id=d.uuid"
+                select_ = ('type', 'd.config as config', 'd.uuid as datacenter_id', 'vim_url', 'vim_url_admin',
+                           'd.name as datacenter_name', 'dt.uuid as datacenter_tenant_id',
+                           'dt.vim_tenant_name as vim_tenant_name', 'dt.vim_tenant_id as vim_tenant_id',
+                           'user', 'passwd', 'dt.config as dt_config')
+                where_ = {"dt.uuid": self.datacenter_tenant_id}
+                vims = self.db.get_rows(FROM=from_, SELECT=select_, WHERE=where_)
+                vim = vims[0]
+                vim_config = {}
+                if vim["config"]:
+                    vim_config.update(yaml.load(vim["config"], Loader=yaml.Loader))
+                if vim["dt_config"]:
+                    vim_config.update(yaml.load(vim["dt_config"], Loader=yaml.Loader))
+                vim_config['datacenter_tenant_id'] = vim.get('datacenter_tenant_id')
+                vim_config['datacenter_id'] = vim.get('datacenter_id')
+
+                # get port_mapping
+                # vim_port_mappings = self.ovim.get_of_port_mappings(
+                #     db_filter={"datacenter_id": vim_config['datacenter_id']})
+                # vim_config["wim_external_ports"] = [x for x in vim_port_mappings
+                #                                     if x["service_mapping_info"].get("wim")]
+                self.plugin_name = "rovim_" + vim["type"]
+                self.vim = self.plugins[self.plugin_name].vimconnector(
+                    uuid=vim['datacenter_id'], name=vim['datacenter_name'],
+                    tenant_id=vim['vim_tenant_id'], tenant_name=vim['vim_tenant_name'],
+                    url=vim['vim_url'], url_admin=vim['vim_url_admin'],
+                    user=vim['user'], passwd=vim['passwd'],
+                    config=vim_config, persistent_info=self.vim_persistent_info
+                )
+                self.error_status = None
+                self.logger.info("Vim Connector loaded for vim_account={}, plugin={}".format(
+                    self.datacenter_tenant_id, self.plugin_name))
+            except Exception as e:
+                self.logger.error("Cannot load vimconnector for vim_account={} plugin={}: {}".format(
+                    self.datacenter_tenant_id, self.plugin_name, e))
+                self.vim = None
+                self.error_status = "Error loading vimconnector: {}".format(e)
+        else:
+            try:
+                wim_account = self.db.get_rows(FROM="wim_accounts", WHERE={"uuid": self.wim_account_id})[0]
+                wim = self.db.get_rows(FROM="wims", WHERE={"uuid": wim_account["wim_id"]})[0]
+                if wim["config"]:
+                    self.sdnconn_config = yaml.load(wim["config"], Loader=yaml.Loader)
+                else:
+                    self.sdnconn_config = {}
+                if wim_account["config"]:
+                    self.sdnconn_config.update(yaml.load(wim_account["config"], Loader=yaml.Loader))
+                self.port_mappings = self.db.get_rows(FROM="wim_port_mappings", WHERE={"wim_id": wim_account["wim_id"]})
+                if self.port_mappings:
+                    self.sdnconn_config["service_endpoint_mapping"] = self.port_mappings
+                self.plugin_name = "rosdn_" + wim["type"]
+                self.sdnconnector = self.plugins[self.plugin_name](
+                    wim, wim_account, config=self.sdnconn_config)
+                self.error_status = None
+                self.logger.info("Sdn Connector loaded for wim_account={}, plugin={}".format(
+                    self.wim_account_id, self.plugin_name))
+            except Exception as e:
+                self.logger.error("Cannot load sdn connector for wim_account={}, plugin={}: {}".format(
+                    self.wim_account_id, self.plugin_name, e))
+                self.sdnconnector = None
+                self.error_status = "Error loading sdn connector: {}".format(e)
 
     def _get_db_task(self):
         """
@@ -202,7 +240,7 @@
             while True:
                 # get 20 (database_limit) entries each time
                 vim_actions = self.db.get_rows(FROM="vim_wim_actions",
-                                               WHERE={"datacenter_vim_id": self.datacenter_tenant_id,
+                                               WHERE={self.target_k: self.target_v,
                                                       "status": ['SCHEDULED', 'BUILD', 'DONE'],
                                                       "worker": [None, self.my_id], "modified_at<=": now
                                                       },
@@ -219,7 +257,7 @@
                     task_related = task["related"]
                     # lock ...
                     self.db.update_rows("vim_wim_actions", UPDATE={"worker": self.my_id}, modified_time=0,
-                                        WHERE={"datacenter_vim_id": self.datacenter_tenant_id,
+                                        WHERE={self.target_k: self.target_v,
                                                "status": ['SCHEDULED', 'BUILD', 'DONE', 'FAILED'],
                                                "worker": [None, self.my_id],
                                                "related": task_related,
@@ -227,7 +265,7 @@
                                                })
                     # ... and read all related and check if locked
                     related_tasks = self.db.get_rows(FROM="vim_wim_actions",
-                                                     WHERE={"datacenter_vim_id": self.datacenter_tenant_id,
+                                                     WHERE={self.target_k: self.target_v,
                                                             "status": ['SCHEDULED', 'BUILD', 'DONE', 'FAILED'],
                                                             "related": task_related,
                                                             "item": task["item"],
@@ -248,7 +286,7 @@
                     if some_tasks_not_locked:
                         if some_tasks_locked:  # unlock
                             self.db.update_rows("vim_wim_actions", UPDATE={"worker": None}, modified_time=0,
-                                                WHERE={"datacenter_vim_id": self.datacenter_tenant_id,
+                                                WHERE={self.target_k: self.target_v,
                                                        "worker": self.my_id,
                                                        "related": task_related,
                                                        "item": task["item"],
@@ -260,7 +298,7 @@
 
                     task["params"] = None
                     if task["extra"]:
-                        extra = yaml.load(task["extra"])
+                        extra = yaml.load(task["extra"], Loader=yaml.Loader)
                     else:
                         extra = {}
                     task["extra"] = extra
@@ -298,7 +336,7 @@
         try:
             # get all related tasks
             related_tasks = self.db.get_rows(FROM="vim_wim_actions",
-                                             WHERE={"datacenter_vim_id": self.datacenter_tenant_id,
+                                             WHERE={self.target_k: self.target_v,
                                                     "status": ['SCHEDULED', 'BUILD', 'DONE', 'FAILED'],
                                                     "action": ["FIND", "CREATE"],
                                                     "related": task["related"],
@@ -310,7 +348,7 @@
                     task_create = related_task
                     # TASK_CREATE
                     if related_task["extra"]:
-                        extra_created = yaml.load(related_task["extra"])
+                        extra_created = yaml.load(related_task["extra"], Loader=yaml.Loader)
                         if extra_created.get("created"):
                             deletion_needed = True
                         related_task["extra"] = extra_created
@@ -321,7 +359,7 @@
 
             # mark task_create as FINISHED
             self.db.update_rows("vim_wim_actions", UPDATE={"status": "FINISHED"},
-                                WHERE={"datacenter_vim_id": self.datacenter_tenant_id,
+                                WHERE={self.target_k: self.target_v,
                                        "instance_action_id": task_create["instance_action_id"],
                                        "task_index": task_create["task_index"]
                                        })
@@ -329,7 +367,7 @@
                 return
             elif dependency_task:
                 # move create information  from task_create to relate_task
-                extra_new_created = yaml.load(dependency_task["extra"]) or {}
+                extra_new_created = yaml.load(dependency_task["extra"], Loader=yaml.Loader) or {}
                 extra_new_created["created"] = extra_created["created"]
                 copy_extra_created(copy_to=extra_new_created, copy_from=extra_created)
 
@@ -337,7 +375,7 @@
                                     UPDATE={"extra": yaml.safe_dump(extra_new_created, default_flow_style=True,
                                                                     width=256),
                                             "vim_id": task_create.get("vim_id")},
-                                    WHERE={"datacenter_vim_id": self.datacenter_tenant_id,
+                                    WHERE={self.target_k: self.target_v,
                                            "instance_action_id": dependency_task["instance_action_id"],
                                            "task_index": dependency_task["task_index"]
                                            })
@@ -379,40 +417,38 @@
             task_vim_interface = task_interface.get("vim_info")
             if task_vim_interface != interface:
                 # delete old port
-                if task_interface.get("sdn_port_id"):
-                    try:
-                        with self.db_lock:
-                            self.ovim.delete_port(task_interface["sdn_port_id"], idempotent=True)
-                            task_interface["sdn_port_id"] = None
-                    except ovimException as e:
-                        error_text = "ovimException deleting external_port={}: {}".format(
-                            task_interface["sdn_port_id"], e)
-                        self.logger.error("task={} get-VM: {}".format(task_id, error_text), exc_info=True)
-                        task_warning_msg += error_text
-                        # TODO Set error_msg at instance_nets instead of instance VMs
+                # if task_interface.get("sdn_port_id"):
+                #     try:
+                #         self.ovim.delete_port(task_interface["sdn_port_id"], idempotent=True)
+                #         task_interface["sdn_port_id"] = None
+                #     except ovimException as e:
+                #         error_text = "ovimException deleting external_port={}: {}".format(
+                #             task_interface["sdn_port_id"], e)
+                #         self.logger.error("task={} get-VM: {}".format(task_id, error_text), exc_info=True)
+                #         task_warning_msg += error_text
+                #         # TODO Set error_msg at instance_nets instead of instance VMs
 
                 # Create SDN port
-                sdn_net_id = task_interface.get("sdn_net_id")
-                if sdn_net_id and interface.get("compute_node") and interface.get("pci"):
-                    sdn_port_name = sdn_net_id + "." + task["vim_id"]
-                    sdn_port_name = sdn_port_name[:63]
-                    try:
-                        with self.db_lock:
-                            sdn_port_id = self.ovim.new_external_port(
-                                {"compute_node": interface["compute_node"],
-                                    "pci": interface["pci"],
-                                    "vlan": interface.get("vlan"),
-                                    "net_id": sdn_net_id,
-                                    "region": self.vim["config"]["datacenter_id"],
-                                    "name": sdn_port_name,
-                                    "mac": interface.get("mac_address")})
-                            task_interface["sdn_port_id"] = sdn_port_id
-                    except (ovimException, Exception) as e:
-                        error_text = "ovimException creating new_external_port compute_node={} pci={} vlan={} {}".\
-                            format(interface["compute_node"], interface["pci"], interface.get("vlan"), e)
-                        self.logger.error("task={} get-VM: {}".format(task_id, error_text), exc_info=True)
-                        task_warning_msg += error_text
-                        # TODO Set error_msg at instance_nets instead of instance VMs
+                # sdn_net_id = task_interface.get("sdn_net_id")
+                # if sdn_net_id and interface.get("compute_node") and interface.get("pci"):
+                #     sdn_port_name = sdn_net_id + "." + task["vim_id"]
+                #     sdn_port_name = sdn_port_name[:63]
+                #     try:
+                #         sdn_port_id = self.ovim.new_external_port(
+                #             {"compute_node": interface["compute_node"],
+                #                 "pci": interface["pci"],
+                #                 "vlan": interface.get("vlan"),
+                #                 "net_id": sdn_net_id,
+                #                 "region": self.vim["config"]["datacenter_id"],
+                #                 "name": sdn_port_name,
+                #                 "mac": interface.get("mac_address")})
+                #         task_interface["sdn_port_id"] = sdn_port_id
+                #     except (ovimException, Exception) as e:
+                #         error_text = "ovimException creating new_external_port compute_node={} pci={} vlan={} {}".\
+                #             format(interface["compute_node"], interface["pci"], interface.get("vlan"), e)
+                #         self.logger.error("task={} get-VM: {}".format(task_id, error_text), exc_info=True)
+                #         task_warning_msg += error_text
+                #         # TODO Set error_msg at instance_nets instead of instance VMs
 
                 self.db.update_rows('instance_interfaces',
                                     UPDATE={"mac_address": interface.get("mac_address"),
@@ -425,6 +461,8 @@
                                             "vlan": interface.get("vlan")},
                                     WHERE={'uuid': task_interface["iface_id"]})
                 task_interface["vim_info"] = interface
+                # if sdn_net_id and interface.get("compute_node") and interface.get("pci"):
+                # # TODO Send message to task SDN to update
 
         # check and update task and instance_vms database
         vim_info_error_msg = None
@@ -468,30 +506,29 @@
         task_vim_info = task["extra"].get("vim_info")
         task_vim_status = task["extra"].get("vim_status")
         task_error_msg = task.get("error_msg")
-        task_sdn_net_id = task["extra"].get("sdn_net_id")
+        # task_sdn_net_id = task["extra"].get("sdn_net_id")
 
         vim_info_status = vim_info["status"]
         vim_info_error_msg = vim_info.get("error_msg")
         # get ovim status
-        if task_sdn_net_id:
-            try:
-                with self.db_lock:
-                    sdn_net = self.ovim.show_network(task_sdn_net_id)
-            except (ovimException, Exception) as e:
-                text_error = "ovimException getting network snd_net_id={}: {}".format(task_sdn_net_id, e)
-                self.logger.error("task={} get-net: {}".format(task_id, text_error), exc_info=True)
-                sdn_net = {"status": "ERROR", "last_error": text_error}
-            if sdn_net["status"] == "ERROR":
-                if not vim_info_error_msg:
-                    vim_info_error_msg = str(sdn_net.get("last_error"))
-                else:
-                    vim_info_error_msg = "VIM_ERROR: {} && SDN_ERROR: {}".format(
-                        self._format_vim_error_msg(vim_info_error_msg, 1024 // 2 - 14),
-                        self._format_vim_error_msg(sdn_net["last_error"], 1024 // 2 - 14))
-                vim_info_status = "ERROR"
-            elif sdn_net["status"] == "BUILD":
-                if vim_info_status == "ACTIVE":
-                    vim_info_status = "BUILD"
+        # if task_sdn_net_id:
+        #     try:
+        #         sdn_net = self.ovim.show_network(task_sdn_net_id)
+        #     except (ovimException, Exception) as e:
+        #         text_error = "ovimException getting network snd_net_id={}: {}".format(task_sdn_net_id, e)
+        #         self.logger.error("task={} get-net: {}".format(task_id, text_error), exc_info=True)
+        #         sdn_net = {"status": "ERROR", "last_error": text_error}
+        #     if sdn_net["status"] == "ERROR":
+        #         if not vim_info_error_msg:
+        #             vim_info_error_msg = str(sdn_net.get("last_error"))
+        #         else:
+        #             vim_info_error_msg = "VIM_ERROR: {} && SDN_ERROR: {}".format(
+        #                 self._format_vim_error_msg(vim_info_error_msg, 1024 // 2 - 14),
+        #                 self._format_vim_error_msg(sdn_net["last_error"], 1024 // 2 - 14))
+        #         vim_info_status = "ERROR"
+        #     elif sdn_net["status"] == "BUILD":
+        #         if vim_info_status == "ACTIVE":
+        #             vim_info_status = "BUILD"
 
         # update database
         if vim_info_error_msg:
@@ -543,7 +580,7 @@
                     # Move this task to the time dependency is going to be modified plus 10 seconds.
                     self.db.update_rows("vim_wim_actions", modified_time=dependency_modified_at + 10,
                                         UPDATE={"worker": None},
-                                        WHERE={"datacenter_vim_id": self.datacenter_tenant_id, "worker": self.my_id,
+                                        WHERE={self.target_k: self.target_v, "worker": self.my_id,
                                                "related": task["related"],
                                                })
                     # task["extra"]["tries"] = task["extra"].get("tries", 0) + 1
@@ -566,7 +603,7 @@
             if task["status"] == "SUPERSEDED":
                 # not needed to do anything but update database with the new status
                 database_update = None
-            elif not self.vim:
+            elif not self.vim and not self.sdnconnector:
                 task["status"] = "FAILED"
                 task["error_msg"] = self.error_status
                 database_update = {"status": "VIM_ERROR", "error_msg": task["error_msg"]}
@@ -575,7 +612,7 @@
                 task["status"] = related_tasks[0]["status"]
                 task["error_msg"] = related_tasks[0]["error_msg"]
                 task["vim_id"] = related_tasks[0]["vim_id"]
-                extra = yaml.load(related_tasks[0]["extra"])
+                extra = yaml.load(related_tasks[0]["extra"], Loader=yaml.Loader)
                 task["extra"]["vim_status"] = extra.get("vim_status")
                 next_refresh = related_tasks[0]["modified_at"] + 0.001
                 database_update = {"status": task["extra"].get("vim_status", "VIM_ERROR"),
@@ -608,6 +645,19 @@
                     database_update = self.get_net(task)
                 else:
                     raise vimconn.vimconnException(self.name + "unknown task action {}".format(task["action"]))
+            elif task["item"] == 'instance_wim_nets':
+                if task["status"] in ('BUILD', 'DONE') and task["action"] in ("FIND", "CREATE"):
+                    database_update = self.new_or_update_sdn_net(task)
+                    create_or_find = True
+                elif task["action"] == "CREATE":
+                    create_or_find = True
+                    database_update = self.new_or_update_sdn_net(task)
+                elif task["action"] == "DELETE":
+                    self.del_sdn_net(task)
+                elif task["action"] == "FIND":
+                    database_update = self.get_sdn_net(task)
+                else:
+                    raise vimconn.vimconnException(self.name + "unknown task action {}".format(task["action"]))
             elif task["item"] == 'instance_sfis':
                 if task["action"] == "CREATE":
                     create_or_find = True
@@ -679,7 +729,7 @@
                             "error_msg": task["error_msg"],
                             },
 
-                    WHERE={"datacenter_vim_id": self.datacenter_tenant_id,
+                    WHERE={self.target_k: self.target_v,
                            "worker": self.my_id,
                            "action": ["FIND", "CREATE"],
                            "related": task["related"],
@@ -696,7 +746,7 @@
             self.db.update_rows(
                 table="vim_wim_actions", modified_time=0,
                 UPDATE={"worker": None},
-                WHERE={"datacenter_vim_id": self.datacenter_tenant_id,
+                WHERE={self.target_k: self.target_v,
                        "worker": self.my_id,
                        "related": task["related"],
                        })
@@ -721,7 +771,7 @@
         try:
             self.task_queue.put(task, False)
             return None
-        except Queue.Full:
+        except queue.Full:
             raise vimconn.vimconnException(self.name + ": timeout inserting a task")
 
     def del_task(self, task):
@@ -736,7 +786,7 @@
     def run(self):
         self.logger.debug("Starting")
         while True:
-            self.get_vimconnector()
+            self.get_vim_sdn_connector()
             self.logger.debug("Vimconnector loaded")
             reload_thread = False
 
@@ -794,7 +844,7 @@
         task["params"] = None
         task["depends"] = {}
         if task["extra"]:
-            extra = yaml.load(task["extra"])
+            extra = yaml.load(task["extra"], Loader=yaml.Loader)
             task["extra"] = extra
             task["params"] = extra.get("params")
         else:
@@ -861,19 +911,18 @@
             return instance_element_update
 
     def del_vm(self, task):
-        task_id = task["instance_action_id"] + "." + str(task["task_index"])
+        # task_id = task["instance_action_id"] + "." + str(task["task_index"])
         vm_vim_id = task["vim_id"]
-        interfaces = task["extra"].get("interfaces", ())
+        # interfaces = task["extra"].get("interfaces", ())
         try:
-            for iface in interfaces.values():
-                if iface.get("sdn_port_id"):
-                    try:
-                        with self.db_lock:
-                            self.ovim.delete_port(iface["sdn_port_id"], idempotent=True)
-                    except ovimException as e:
-                        self.logger.error("task={} del-VM: ovimException when deleting external_port={}: {} ".format(
-                            task_id, iface["sdn_port_id"], e), exc_info=True)
-                        # TODO Set error_msg at instance_nets
+            # for iface in interfaces.values():
+            #     if iface.get("sdn_port_id"):
+            #         try:
+            #             self.ovim.delete_port(iface["sdn_port_id"], idempotent=True)
+            #         except ovimException as e:
+            #             self.logger.error("task={} del-VM: ovimException when deleting external_port={}: {} ".format(
+            #                 task_id, iface["sdn_port_id"], e), exc_info=True)
+            #             # TODO Set error_msg at instance_nets
 
             self.vim.delete_vminstance(vm_vim_id, task["extra"].get("created_items"))
             task["status"] = "FINISHED"  # with FINISHED instead of DONE it will not be refreshing
@@ -942,7 +991,6 @@
 
     def new_net(self, task):
         vim_net_id = None
-        sdn_net_id = None
         task_id = task["instance_action_id"] + "." + str(task["task_index"])
         action_text = ""
         try:
@@ -961,89 +1009,70 @@
 
             vim_net_id, created_items = self.vim.new_network(*params[0:5])
 
-            net_name = params[0]
-            net_type = params[1]
-            wim_account_name = None
-            if len(params) >= 5:
-                wim_account_name = params[5]
+            # net_name = params[0]
+            # net_type = params[1]
+            # wim_account_name = None
+            # if len(params) >= 6:
+            #     wim_account_name = params[5]
 
-            sdn_controller = self.vim.config.get('sdn-controller')
-            if sdn_controller and (net_type == "data" or net_type == "ptp"):
-                network = {"name": net_name, "type": net_type, "region": self.vim["config"]["datacenter_id"]}
-
-                vim_net = self.vim.get_network(vim_net_id)
-                if vim_net.get('encapsulation') != 'vlan':
-                    raise vimconn.vimconnException(
-                        "net '{}' defined as type '{}' has not vlan encapsulation '{}'".format(
-                            net_name, net_type, vim_net['encapsulation']))
-                network["vlan"] = vim_net.get('segmentation_id')
-                action_text = "creating SDN"
-                with self.db_lock:
-                    sdn_net_id = self.ovim.new_network(network)
-
-                if wim_account_name and self.vim.config["wim_external_ports"]:
-                    # add external port to connect WIM. Try with compute node __WIM:wim_name and __WIM
-                    action_text = "attaching external port to ovim network"
-                    sdn_port_name = "external_port"
-                    sdn_port_data = {
-                        "compute_node": "__WIM:" + wim_account_name[0:58],
-                        "pci": None,
-                        "vlan": network["vlan"],
-                        "net_id": sdn_net_id,
-                        "region": self.vim["config"]["datacenter_id"],
-                        "name": sdn_port_name,
-                    }
-                    try:
-                        with self.db_lock:
-                            sdn_external_port_id = self.ovim.new_external_port(sdn_port_data)
-                    except ovimException:
-                        sdn_port_data["compute_node"] = "__WIM"
-                        with self.db_lock:
-                            sdn_external_port_id = self.ovim.new_external_port(sdn_port_data)
-                    self.logger.debug("Added sdn_external_port {} to sdn_network {}".format(sdn_external_port_id,
-                                                                                            sdn_net_id))
+            # TODO fix at nfvo adding external port
+            # if wim_account_name and self.vim.config["wim_external_ports"]:
+            #     # add external port to connect WIM. Try with compute node __WIM:wim_name and __WIM
+            #     action_text = "attaching external port to ovim network"
+            #     sdn_port_name = "external_port"
+            #     sdn_port_data = {
+            #         "compute_node": "__WIM:" + wim_account_name[0:58],
+            #         "pci": None,
+            #         "vlan": network["vlan"],
+            #         "net_id": sdn_net_id,
+            #         "region": self.vim["config"]["datacenter_id"],
+            #         "name": sdn_port_name,
+            #     }
+            #     try:
+            #         sdn_external_port_id = self.ovim.new_external_port(sdn_port_data)
+            #     except ovimException:
+            #         sdn_port_data["compute_node"] = "__WIM"
+            #         sdn_external_port_id = self.ovim.new_external_port(sdn_port_data)
+            #     self.logger.debug("Added sdn_external_port {} to sdn_network {}".format(sdn_external_port_id,
+            #                                                                             sdn_net_id))
             task["status"] = "DONE"
             task["extra"]["vim_info"] = {}
-            task["extra"]["sdn_net_id"] = sdn_net_id
+            # task["extra"]["sdn_net_id"] = sdn_net_id
             task["extra"]["vim_status"] = "BUILD"
             task["extra"]["created"] = True
             task["extra"]["created_items"] = created_items
             task["error_msg"] = None
             task["vim_id"] = vim_net_id
-            instance_element_update = {"vim_net_id": vim_net_id, "sdn_net_id": sdn_net_id, "status": "BUILD",
+            instance_element_update = {"vim_net_id": vim_net_id, "status": "BUILD",
                                        "created": True, "error_msg": None}
             return instance_element_update
-        except (vimconn.vimconnException, ovimException) as e:
+        except vimconn.vimconnException as e:
             self.logger.error("task={} new-net: Error {}: {}".format(task_id, action_text, e))
             task["status"] = "FAILED"
             task["vim_id"] = vim_net_id
             task["error_msg"] = self._format_vim_error_msg(str(e))
-            task["extra"]["sdn_net_id"] = sdn_net_id
-            instance_element_update = {"vim_net_id": vim_net_id, "sdn_net_id": sdn_net_id, "status": "VIM_ERROR",
+            # task["extra"]["sdn_net_id"] = sdn_net_id
+            instance_element_update = {"vim_net_id": vim_net_id, "status": "VIM_ERROR",
                                        "error_msg": task["error_msg"]}
             return instance_element_update
 
     def del_net(self, task):
         net_vim_id = task["vim_id"]
-        sdn_net_id = task["extra"].get("sdn_net_id")
+        # sdn_net_id = task["extra"].get("sdn_net_id")
         try:
             if net_vim_id:
                 self.vim.delete_network(net_vim_id, task["extra"].get("created_items"))
-            if sdn_net_id:
-                # Delete any attached port to this sdn network. There can be ports associated to this network in case
-                # it was manually done using 'openmano vim-net-sdn-attach'
-                with self.db_lock:
-                    port_list = self.ovim.get_ports(columns={'uuid'},
-                                                    filter={'name': 'external_port', 'net_id': sdn_net_id})
-                    for port in port_list:
-                        self.ovim.delete_port(port['uuid'], idempotent=True)
-                    self.ovim.delete_network(sdn_net_id, idempotent=True)
+            # if sdn_net_id:
+            #     # Delete any attached port to this sdn network. There can be ports associated to this network in case
+            #     # it was manually done using 'openmano vim-net-sdn-attach'
+            #     port_list = self.ovim.get_ports(columns={'uuid'},
+            #                                     filter={'name': 'external_port', 'net_id': sdn_net_id})
+            #     for port in port_list:
+            #         self.ovim.delete_port(port['uuid'], idempotent=True)
+            #     self.ovim.delete_network(sdn_net_id, idempotent=True)
             task["status"] = "FINISHED"  # with FINISHED instead of DONE it will not be refreshing
             task["error_msg"] = None
             return None
-        except ovimException as e:
-            task["error_msg"] = self._format_vim_error_msg("ovimException obtaining and deleting external "
-                                                           "ports for net {}: {}".format(sdn_net_id, str(e)))
         except vimconn.vimconnException as e:
             task["error_msg"] = self._format_vim_error_msg(str(e))
             if isinstance(e, vimconn.vimconnNotFoundException):
@@ -1053,6 +1082,160 @@
         task["status"] = "FAILED"
         return None
 
+    def new_or_update_sdn_net(self, task):
+        wimconn_net_id = task["vim_id"]
+        created_items = task["extra"].get("created_items")
+        connected_ports = task["extra"].get("connected_ports", [])
+        new_connected_ports = []
+        last_update = task["extra"].get("last_update", 0)
+        sdn_status = "BUILD"
+        sdn_info = None
+
+        task_id = task["instance_action_id"] + "." + str(task["task_index"])
+        error_list = []
+        try:
+            # FIND
+            if task["extra"].get("find"):
+                wimconn_id = task["extra"]["find"][0]
+                try:
+                    instance_element_update = self.sdnconnector.get_connectivity_service_status(wimconn_id)
+                    wimconn_net_id = wimconn_id
+                    instance_element_update = {"wim_internal_id": wimconn_net_id, "created": False, "status": "BUILD",
+                                               "error_msg": None, }
+                    return instance_element_update
+                except Exception as e:
+                    if isinstance(e, SdnConnectorError) and e.http_error == HTTPStatus.NOT_FOUND.value:
+                        pass
+                    else: 
+                        self._proccess_sdn_exception(e)
+
+            params = task["params"]
+            # CREATE
+            # look for ports
+            sdn_ports = []
+            pending_ports = 0
+
+            ports = self.db.get_rows(FROM='instance_interfaces', WHERE={'instance_wim_net_id': task["item_id"]})
+            sdn_need_update = False
+            for port in ports:
+                # TODO. Do not connect if already done
+                if port.get("compute_node") and port.get("pci"):
+                    for map in self.port_mappings:
+                        if map.get("device_id") == port["compute_node"] and \
+                                map.get("device_interface_id") == port["pci"]:
+                            break
+                    else:
+                        if self.sdnconn_config.get("mapping_not_needed"):
+                            map = {
+                                "service_endpoint_id": "{}:{}".format(port["compute_node"], port["pci"]),
+                                "service_endpoint_encapsulation_info": {
+                                    "vlan": port["vlan"],
+                                    "mac": port["mac_address"],
+                                    "device_id": port["compute_node"],
+                                    "device_interface_id": port["pci"]
+                                }
+                            }
+                        else:
+                            map = None
+                            error_list.append("Port mapping not found for compute_node={} pci={}".format(
+                                port["compute_node"], port["pci"]))
+
+                    if map:
+                        if port["uuid"] not in connected_ports or port["modified_at"] > last_update:
+                            sdn_need_update = True
+                        new_connected_ports.append(port["uuid"])
+                        sdn_ports.append({
+                            "service_endpoint_id": map["service_endpoint_id"],
+                            "service_endpoint_encapsulation_type": "dot1q" if port["model"] == "SR-IOV" else None,
+                            "service_endpoint_encapsulation_info": {
+                                "vlan": port["vlan"],
+                                "mac": port["mac_address"],
+                                "device_id": map.get("device_id"),
+                                "device_interface_id": map.get("device_interface_id"),
+                                "switch_dpid": map.get("switch_dpid"),
+                                "switch_port": map.get("switch_port"),
+                                "service_mapping_info": map.get("service_mapping_info"),
+                            }
+                        })
+
+                else:
+                    pending_ports += 1
+            if pending_ports:
+                error_list.append("Waiting for getting interfaces location from VIM. Obtained '{}' of {}"
+                                  .format(len(ports)-pending_ports, len(ports)))
+            # if there are more ports to connect or they have been modified, call create/update
+            if sdn_need_update and len(sdn_ports) >= 2:
+                if not wimconn_net_id:
+                    if params[0] == "data":
+                        net_type = "ELAN"
+                    elif params[0] == "ptp":
+                        net_type = "ELINE"
+                    else:
+                        net_type = "L3"
+
+                    wimconn_net_id, created_items = self.sdnconnector.create_connectivity_service(net_type, sdn_ports)
+                else:
+                    created_items = self.sdnconnector.edit_connectivity_service(wimconn_net_id, conn_info=created_items,
+                                                                                connection_points=sdn_ports)
+                last_update = time.time()
+                connected_ports = new_connected_ports
+            elif wimconn_net_id:
+                try: 
+                    wim_status_dict = self.sdnconnector.get_connectivity_service_status(wimconn_net_id,
+                                                                                        conn_info=created_items)
+                    sdn_status = wim_status_dict["sdn_status"]
+                    if wim_status_dict.get("error_msg"):
+                        error_list.append(wim_status_dict.get("error_msg"))
+                    if wim_status_dict.get("sdn_info"):
+                        sdn_info = str(wim_status_dict.get("sdn_info"))
+                except Exception as e:
+                    self._proccess_sdn_exception(e)
+
+            task["status"] = "DONE"
+            task["extra"]["vim_info"] = {}
+            # task["extra"]["sdn_net_id"] = sdn_net_id
+            task["extra"]["vim_status"] = "BUILD"
+            task["extra"]["created"] = True
+            task["extra"]["created_items"] = created_items
+            task["extra"]["connected_ports"] = connected_ports
+            task["extra"]["last_update"] = last_update
+            task["error_msg"] = self._format_vim_error_msg(" ; ".join(error_list))
+            task["vim_id"] = wimconn_net_id
+            instance_element_update = {"wim_internal_id": wimconn_net_id, "status": sdn_status,
+                                       "created": True, "error_msg": task["error_msg"] or None}
+        except (vimconn.vimconnException, SdnConnectorError) as e:
+            self.logger.error("task={} new-sdn-net: Error: {}".format(task_id, e))
+            task["status"] = "FAILED"
+            task["vim_id"] = wimconn_net_id
+            task["error_msg"] = self._format_vim_error_msg(str(e))
+            # task["extra"]["sdn_net_id"] = sdn_net_id
+            instance_element_update = {"wim_internal_id": wimconn_net_id, "status": "WIM_ERROR",
+                                       "error_msg": task["error_msg"]}
+        if sdn_info:
+            instance_element_update["wim_info"] = sdn_info
+        return instance_element_update
+
+    def del_sdn_net(self, task):
+        wimconn_net_id = task["vim_id"]
+        try:
+            try:
+                if wimconn_net_id:
+                    self.sdnconnector.delete_connectivity_service(wimconn_net_id, task["extra"].get("created_items"))
+                task["status"] = "FINISHED"  # with FINISHED instead of DONE it will not be refreshing
+                task["error_msg"] = None
+                return None
+            except Exception as e:
+                self._proccess_sdn_exception(e)
+        except SdnConnectorError as e:
+            task["error_msg"] = self._format_vim_error_msg(str(e))
+            if e.http_code == HTTPStatus.NOT_FOUND.value:
+                # If not found mark as Done and fill error_msg
+                task["status"] = "FINISHED"  # with FINISHED instead of DONE it will not be refreshing
+                task["error_msg"] = None
+                return None
+        task["status"] = "FAILED"
+        return None
+
     # Service Function Instances
     def new_sfi(self, task):
         vim_sfi_id = None
@@ -1068,12 +1251,12 @@
             egress_interface_id = task.get("extra").get("params").get("egress_interface_id")
             ingress_vim_interface_id = None
             egress_vim_interface_id = None
-            for vim_interface, interface_data in interfaces.iteritems():
+            for vim_interface, interface_data in interfaces.items():
                 if interface_data.get("interface_id") == ingress_interface_id:
                     ingress_vim_interface_id = vim_interface
                     break
             if ingress_interface_id != egress_interface_id:
-                for vim_interface, interface_data in interfaces.iteritems():
+                for vim_interface, interface_data in interfaces.items():
                     if interface_data.get("interface_id") == egress_interface_id:
                         egress_vim_interface_id = vim_interface
                         break
@@ -1092,7 +1275,7 @@
             # only the first ingress and first egress ports will be used to create the SFI (Port Pair).
             ingress_port_id_list = [ingress_vim_interface_id]
             egress_port_id_list = [egress_vim_interface_id]
-            name = "sfi-%s" % task["item_id"][:8]
+            name = "sfi-{}".format(task["item_id"][:8])
             # By default no form of IETF SFC Encapsulation will be used
             vim_sfi_id = self.vim.new_sfi(name, ingress_port_id_list, egress_port_id_list, sfc_encap=False)
 
@@ -1136,12 +1319,12 @@
             task_id = task["instance_action_id"] + "." + str(task["task_index"])
             error_text = ""
             depending_tasks = ["TASK-" + str(dep_id) for dep_id in task["extra"]["depends_on"]]
-            # sfis = task.get("depends").values()[0].get("extra").get("params")[5]
+            # sfis = next(iter(task.get("depends").values())).get("extra").get("params")[5]
             sfis = [task.get("depends").get(dep_task) for dep_task in depending_tasks]
             sfi_id_list = []
             for sfi in sfis:
                 sfi_id_list.append(sfi.get("vim_id"))
-            name = "sf-%s" % task["item_id"][:8]
+            name = "sf-{}".format(task["item_id"][:8])
             # By default no form of IETF SFC Encapsulation will be used
             vim_sf_id = self.vim.new_sf(name, sfi_id_list, sfc_encap=False)
 
@@ -1192,7 +1375,7 @@
             # to create the Classification(s) (the "logical source port" of the "Flow Classifier").
             # Since the VNFFG classifier match lacks the ethertype, classification defaults to
             # using the IPv4 flow classifier.
-            name = "c-%s" % task["item_id"][:8]
+            name = "c-{}".format(task["item_id"][:8])
             # if not CIDR is given for the IP addresses, add /32:
             ip_proto = int(params.get("ip_proto"))
             source_ip = params.get("source_ip")
@@ -1278,7 +1461,7 @@
                 elif resource == "instance_classifications":
                     classification_id_list.append(vim_id)
 
-            name = "sfp-%s" % task["item_id"][:8]
+            name = "sfp-{}".format(task["item_id"][:8])
             # By default no form of IETF SFC Encapsulation will be used
             vim_sfp_id = self.vim.new_sfp(name, classification_id_list, sf_id_list, sfc_encap=False)
 
diff --git a/osm_ro/vimconn.py b/RO/osm_ro/vimconn.py
similarity index 99%
rename from osm_ro/vimconn.py
rename to RO/osm_ro/vimconn.py
index 14068e9..c97370d 100644
--- a/osm_ro/vimconn.py
+++ b/RO/osm_ro/vimconn.py
@@ -29,12 +29,12 @@
 import logging
 import paramiko
 import socket
-import StringIO
+from io import StringIO
 import yaml
 import sys
 from email.mime.multipart import MIMEMultipart
 from email.mime.text import MIMEText
-from utils import deprecated
+from osm_ro.utils import deprecated
 
 __author__ = "Alfonso Tierno, Igor D.C."
 __date__  = "$14-aug-2017 23:59:59$"
@@ -635,12 +635,12 @@
         elif not ro_key and not password:
             raise vimconnNotSupportedException("All parameters should be different from 'None'")
         else:
-            commands = {'mkdir -p ~/.ssh/', 'echo "%s" >> ~/.ssh/authorized_keys' % key,
+            commands = {'mkdir -p ~/.ssh/', 'echo "{}" >> ~/.ssh/authorized_keys'.format(key),
                         'chmod 644 ~/.ssh/authorized_keys', 'chmod 700 ~/.ssh/'}
             client = paramiko.SSHClient()
             try:
                 if ro_key:
-                    pkey = paramiko.RSAKey.from_private_key(StringIO.StringIO(ro_key))
+                    pkey = paramiko.RSAKey.from_private_key(StringIO(ro_key))
                 else:
                     pkey = None
                 client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
diff --git a/osm_ro/vmwarecli.py b/RO/osm_ro/vmwarecli.py
similarity index 95%
rename from osm_ro/vmwarecli.py
rename to RO/osm_ro/vmwarecli.py
index 80fe394..b7b2742 100755
--- a/osm_ro/vmwarecli.py
+++ b/RO/osm_ro/vmwarecli.py
@@ -67,17 +67,17 @@
 from pyvcloud import Http
 
 import logging
-import vimconn
+from osm_ro import vimconn
 import time
 import uuid
 import urllib3
 import requests
 
-from vimconn_vmware import vimconnector
-from requests.packages.urllib3.exceptions import InsecureRequestWarning
+from osm_ro.vimconn_vmware import vimconnector
+# TODO py3 uncoment  from requests.packages.urllib3.exceptions import InsecureRequestWarning
 from prettytable import PrettyTable
 
-requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
+# TODO py3 uncoment requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
 
 __author__ = "Mustafa Bayramov"
 __date__ = "$16-Sep-2016 11:09:29$"
@@ -108,7 +108,7 @@
                             verify=vca.verify,
                             logger=vca.logger)
         if response.status_code == requests.codes.ok:
-            print response.content
+            print(response.content)
             return response.content
 
     return None
@@ -161,7 +161,7 @@
 
         vm_table.add_row(entry)
 
-    print vm_table
+    print(vm_table)
 
 
 def print_org(org_dict=None):
@@ -182,7 +182,7 @@
         entry = [k, org_dict[k]]
         org_table.add_row(entry)
 
-    print org_table
+    print(org_table)
 
 
 def print_vm_list(vm_dict=None):
@@ -213,7 +213,7 @@
             entry.append(vm_dict[k]['memoryMB'])
             entry.append(vm_dict[k]['status'])
             vm_table.add_row(entry)
-        print vm_table
+        print(vm_table)
     except KeyError:
         logger.error("wrong key {}".format(KeyError.message))
         pass
@@ -232,14 +232,14 @@
         return
     try:
         vdcs_dict = {}
-        if org_dict.has_key('vdcs'):
+        if 'vdcs' in org_dict:
             vdcs_dict = org_dict['vdcs']
         vdc_table = PrettyTable(['vdc uuid', 'vdc name'])
         for k in vdcs_dict:
             entry = [k, vdcs_dict[k]]
             vdc_table.add_row(entry)
 
-        print vdc_table
+        print(vdc_table)
     except KeyError:
         logger.error("wrong key {}".format(KeyError.message))
         logger.logger.debug(traceback.format_exc())
@@ -259,14 +259,14 @@
         return
     try:
         network_dict = {}
-        if org_dict.has_key('networks'):
+        if 'networks' in org_dict:
             network_dict = org_dict['networks']
         network_table = PrettyTable(['network uuid', 'network name'])
         for k in network_dict:
             entry = [k, network_dict[k]]
             network_table.add_row(entry)
 
-        print network_table
+        print(network_table)
 
     except KeyError:
         logger.error("wrong key {}".format(KeyError.message))
@@ -290,7 +290,7 @@
         print_vdc_list(org_dict=org_dict)
         print_network_list(org_dict=org_dict)
 
-        if org_dict.has_key('catalogs'):
+        if 'catalogs' in org_dict:
             catalogs_dict = org_dict['catalogs']
 
         catalog_table = PrettyTable(['catalog uuid', 'catalog name'])
@@ -298,7 +298,7 @@
             entry = [k, catalogs_dict[k]]
             catalog_table.add_row(entry)
 
-        print catalog_table
+        print(catalog_table)
 
     except KeyError:
         logger.error("wrong key {}".format(KeyError.message))
@@ -369,9 +369,9 @@
 def print_network_details(network_dict=None):
     try:
         network_table = PrettyTable(network_dict.keys())
-        entry = [network_dict.values()]
+        entry = list(network_dict.values())
         network_table.add_row(entry[0])
-        print network_table
+        print(network_table)
     except KeyError:
         logger.error("wrong key {}".format(KeyError.message))
         logger.logger.debug(traceback.format_exc())
@@ -382,9 +382,9 @@
     try:
         for element in generic_dict:
             table = PrettyTable(element.keys())
-            entry = [element.values()]
+            entry = list(element.values())
             table.add_row(entry[0])
-        print table
+        print(table)
     except KeyError:
         logger.error("wrong key {}".format(KeyError.message))
         logger.logger.debug(traceback.format_exc())
@@ -433,10 +433,10 @@
                     print("Can't find vapp by given name {}".format(namespace.vapp_name))
                     return
 
-            print " namespace {}".format(namespace)
+            print(" namespace {}".format(namespace))
             if vapp_dict is not None and namespace.osm:
                 vm_info_dict = vim.get_vminstance(vim_vm_uuid=vapp_uuid)
-                print vm_info_dict
+                print(vm_info_dict)
             if vapp_dict is not None and namespace.osm != True:
                 vapp_dict = vim.get_vapp(vdc_name=namespace.vcdvdc, vapp_name=vapp_uuid, isuuid=True)
                 print_vapp(vapp_dict=vapp_dict)
@@ -448,7 +448,7 @@
         # if request name based we need find UUID
         # TODO optimize it or move to external function
         if not namespace.uuid:
-            if not myorg.has_key('networks'):
+            if 'networks' not in myorg:
                 print("Network {} is undefined in vcloud director for org {} vdc {}".format(namespace.network_name,
                                                                                             vim.name,
                                                                                             vim.tenant_name))
@@ -460,7 +460,7 @@
                     network_uuid = network
                     break
 
-        print print_network_details(network_dict=vim.get_vcd_network(network_uuid=network_uuid))
+        print(print_network_details(network_dict=vim.get_vcd_network(network_uuid=network_uuid)))
 
 
 def create_actions(vim=None, action=None, namespace=None):
@@ -477,16 +477,16 @@
         logger.debug("Creating a network in vcloud director".format(namespace.network_name))
         network_uuid = vim.create_network(namespace.network_name)
         if network_uuid is not None:
-            print ("Crated new network {} and uuid: {}".format(namespace.network_name, network_uuid))
+            print("Crated new network {} and uuid: {}".format(namespace.network_name, network_uuid))
         else:
-            print ("Failed create a new network {}".format(namespace.network_name))
+            print("Failed create a new network {}".format(namespace.network_name))
     elif action == 'vdc' or namespace.action == 'vdc':
         logger.debug("Creating a new vdc in vcloud director.".format(namespace.vdc_name))
         vdc_uuid = vim.create_vdc(namespace.vdc_name)
         if vdc_uuid is not None:
-            print ("Crated new vdc {} and uuid: {}".format(namespace.vdc_name, vdc_uuid))
+            print("Crated new vdc {} and uuid: {}".format(namespace.vdc_name, vdc_uuid))
         else:
-            print ("Failed create a new vdc {}".format(namespace.vdc_name))
+            print("Failed create a new vdc {}".format(namespace.vdc_name))
     else:
         return None
 
@@ -553,7 +553,7 @@
             if vim_catalog is None:
                 return None
 
-        print (" Booting {} image id {} ".format(vm_name, vim_catalog))
+        print(" Booting {} image id {} ".format(vm_name, vim_catalog))
         vm_uuid, _ = vim.new_vminstance(name=vm_name, image_id=vim_catalog)
         if vm_uuid is not None and validate_uuid4(vm_uuid):
             print("Image booted and vm uuid {}".format(vm_uuid))
@@ -606,9 +606,6 @@
     vcdhost = None
     vcdorg = None
 
-    if hasattr(__builtins__, 'raw_input'):
-        input = raw_input
-
     if namespace.vcdvdc is None:
         while True:
             vcduser = input("Enter vcd username: ")
diff --git a/RO/osm_ro/wim/__init__.py b/RO/osm_ro/wim/__init__.py
new file mode 100644
index 0000000..7284a2b
--- /dev/null
+++ b/RO/osm_ro/wim/__init__.py
@@ -0,0 +1,13 @@
+##
+# 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.
+##
diff --git a/osm_ro/wim/actions.py b/RO/osm_ro/wim/actions.py
similarity index 99%
rename from osm_ro/wim/actions.py
rename to RO/osm_ro/wim/actions.py
index f224460..e199fd0 100644
--- a/osm_ro/wim/actions.py
+++ b/RO/osm_ro/wim/actions.py
@@ -36,9 +36,6 @@
 """Common logic for task management"""
 import logging
 from time import time
-from types import StringTypes
-
-from six.moves import range
 
 import yaml
 
@@ -412,7 +409,7 @@
 
 def _expand_extra(record):
     extra = record.pop('extra', None) or {}
-    if isinstance(extra, StringTypes):
+    if isinstance(extra, str):
         extra = yaml.safe_load(extra)
 
     record['params'] = extra.get('params')
diff --git a/osm_ro/wim/engine.py b/RO/osm_ro/wim/engine.py
similarity index 92%
rename from osm_ro/wim/engine.py
rename to RO/osm_ro/wim/engine.py
index 3fdd032..6a232a4 100644
--- a/osm_ro/wim/engine.py
+++ b/RO/osm_ro/wim/engine.py
@@ -48,33 +48,42 @@
 from contextlib import contextmanager
 from itertools import groupby
 from operator import itemgetter
-from sys import exc_info
+# from sys import exc_info
 from uuid import uuid4
 
-from six import reraise
-
 from ..utils import remove_none_items
 from .actions import Action
 from .errors import (
     DbBaseException,
     NoWimConnectedToDatacenters,
     UnexpectedDatabaseError,
-    WimAccountNotActive
+    WimAccountNotActive,
+    UndefinedWimConnector
 )
 from .wim_thread import WimThread
+# from ..http_tools.errors import Bad_Request
+from pkg_resources import iter_entry_points
 
 
 class WimEngine(object):
     """Logic supporting the establishment of WAN links when NS spans across
     different datacenters.
     """
-    def __init__(self, persistence, logger=None, ovim=None):
+    def __init__(self, persistence, plugins, logger=None, ovim=None):
         self.persist = persistence
+        self.plugins = plugins if plugins is not None else {}
         self.logger = logger or logging.getLogger('openmano.wim.engine')
         self.threads = {}
         self.connectors = {}
         self.ovim = ovim
 
+    def _load_plugin(self, name, type="sdn"):
+        # type can be vim or sdn
+        for v in iter_entry_points('osm_ro{}.plugins'.format(type), name):
+            self.plugins[name] = v.load()
+        if name and name not in self.plugins:
+            raise UndefinedWimConnector(type, name)
+
     def create_wim(self, properties):
         """Create a new wim record according to the properties
 
@@ -90,18 +99,22 @@
         """
         port_mapping = ((properties.get('config', {}) or {})
                         .pop('wim_port_mapping', {}))
+        plugin_name = "rosdn_" + properties["type"]
+        if plugin_name not in self.plugins:
+            self._load_plugin(plugin_name, type="sdn")
+
         uuid = self.persist.create_wim(properties)
 
         if port_mapping:
             try:
                 self.create_wim_port_mappings(uuid, port_mapping)
-            except DbBaseException:
+            except DbBaseException as e:
                 # Rollback
                 self.delete_wim(uuid)
                 ex = UnexpectedDatabaseError('Failed to create port mappings'
                                              'Rolling back wim creation')
                 self.logger.exception(str(ex))
-                reraise(ex.__class__, ex, exc_info()[2])
+                raise ex from e
 
         return uuid
 
@@ -139,13 +152,13 @@
                 self.persist.delete_wim_port_mappings(uuid)
                 # ^  Calling from persistence avoid reloading twice the thread
                 self.create_wim_port_mappings(uuid, port_mapping)
-            except DbBaseException:
+            except DbBaseException as e:
                 # Rollback
                 self.update_wim(uuid_or_name, orig_props)
                 ex = UnexpectedDatabaseError('Failed to update port mappings'
                                              'Rolling back wim updates\n')
                 self.logger.exception(str(ex))
-                reraise(ex.__class__, ex, exc_info()[2])
+                raise ex from e
 
         return response
 
@@ -417,7 +430,7 @@
         past"""
         if instance_scenario_id:
             wan_links = self.persist.get_wan_links(
-                instance_scenario_id=instance_scenario_id)
+                instance_scenario_id=instance_scenario_id, sdn='false')
         return [self.delete_action(l) for l in wan_links]
 
     def incorporate_actions(self, wim_actions, instance_action):
@@ -468,7 +481,7 @@
         """
         thread = None
         try:
-            thread = WimThread(self.persist, wim_account, ovim=self.ovim)
+            thread = WimThread(self.persist, self.plugins, wim_account, ovim=self.ovim)
             self.threads[wim_account['uuid']] = thread
             thread.start()
         except:  # noqa
@@ -480,14 +493,22 @@
     def start_threads(self):
         """Start the threads responsible for processing WIM Actions"""
         accounts = self.persist.get_wim_accounts(error_if_none=False)
-        self.threads = remove_none_items(
-            {a['uuid']: self._spawn_thread(a) for a in accounts})
+        thread_dict = {}
+        for account in accounts:
+            try:
+                plugin_name = "rosdn_" + account["wim"]["type"]
+                if plugin_name not in self.plugins:
+                    self._load_plugin(plugin_name, type="sdn")
+                thread_dict[account["uuid"]] = self._spawn_thread(account)
+            except UndefinedWimConnector as e:
+                self.logger.error(e)
+        self.threads = remove_none_items(thread_dict)
 
     def stop_threads(self):
         """Stop the threads responsible for processing WIM Actions"""
         for uuid, thread in self.threads.items():
             thread.exit()
-            del self.threads[uuid]
+        self.threads.clear()
 
     @contextmanager
     def threads_running(self):
diff --git a/osm_ro/wim/errors.py b/RO/osm_ro/wim/errors.py
similarity index 94%
rename from osm_ro/wim/errors.py
rename to RO/osm_ro/wim/errors.py
index ca8c2b7..8fd0a88 100644
--- a/osm_ro/wim/errors.py
+++ b/RO/osm_ro/wim/errors.py
@@ -31,7 +31,7 @@
 # funded by the European Commission under Grant number 761727 through the
 # Horizon 2020 and 5G-PPP programmes.
 ##
-from six.moves import queue
+import queue
 
 from ..db_base import db_base_Exception as DbBaseException
 from ..http_tools.errors import (
@@ -103,12 +103,10 @@
 class UndefinedWimConnector(DbBaseException):
     """The connector class for the specified wim type is not implemented"""
 
-    def __init__(self, wim_type, module_name, location_reference):
-        super(UndefinedWimConnector, self).__init__(
-            ('{}: `{}`. Could not find module `{}` '
-             '(check if it is necessary to install a plugin)'
-             .format(self.__class__.__doc__, wim_type, module_name)),
-            http_code=Bad_Request)
+    def __init__(self, wim_type, module_name):
+        super(UndefinedWimConnector, self).__init__("Cannot load a module for {t} type '{n}'. The plugin 'osm_{n}' has"
+                                                    " not been registered".format(t=wim_type, n=module_name),
+                                                    http_code=Bad_Request)
 
 
 class WimAccountOverwrite(DbBaseException):
diff --git a/osm_ro/wim/failing_connector.py b/RO/osm_ro/wim/failing_connector.py
similarity index 82%
rename from osm_ro/wim/failing_connector.py
rename to RO/osm_ro/wim/failing_connector.py
index b66551c..6bbab35 100644
--- a/osm_ro/wim/failing_connector.py
+++ b/RO/osm_ro/wim/failing_connector.py
@@ -37,7 +37,7 @@
 execute any action
 """
 import json
-from .wimconn import WimConnectorError
+from .sdnconn import SdnConnectorError
 
 
 class FailingConnector(object):
@@ -51,32 +51,38 @@
     def __init__(self, error_msg):
         self.error_msg = error_msg
 
+    def __call__(self, wim, wim_account, config=None, logger=None):
+        return self
+
+    def vimconnector(self, *args, **kwargs):
+        raise Exception(self.error_msg)
+
     def check_credentials(self):
-        raise WimConnectorError('Impossible to use WIM:\n' + self.error_msg)
+        raise SdnConnectorError('Impossible to use WIM:\n' + self.error_msg)
 
     def get_connectivity_service_status(self, service_uuid, _conn_info=None):
-        raise WimConnectorError('Impossible to retrieve status for {}\n\n{}'
+        raise SdnConnectorError('Impossible to retrieve status for {}\n\n{}'
                                 .format(service_uuid, self.error_msg))
 
     def create_connectivity_service(self, service_uuid, *args, **kwargs):
-        raise WimConnectorError('Impossible to connect {}.\n{}\n{}\n{}'
+        raise SdnConnectorError('Impossible to connect {}.\n{}\n{}\n{}'
                                 .format(service_uuid, self.error_msg,
                                         json.dumps(args, indent=4),
                                         json.dumps(kwargs, indent=4)))
 
     def delete_connectivity_service(self, service_uuid, _conn_info=None):
-        raise WimConnectorError('Impossible to disconnect {}\n\n{}'
+        raise SdnConnectorError('Impossible to disconnect {}\n\n{}'
                                 .format(service_uuid, self.error_msg))
 
     def edit_connectivity_service(self, service_uuid, *args, **kwargs):
-        raise WimConnectorError('Impossible to change connection {}.\n{}\n'
+        raise SdnConnectorError('Impossible to change connection {}.\n{}\n'
                                 '{}\n{}'
                                 .format(service_uuid, self.error_msg,
                                         json.dumps(args, indent=4),
                                         json.dumps(kwargs, indent=4)))
 
     def clear_all_connectivity_services(self):
-        raise WimConnectorError('Impossible to use WIM:\n' + self.error_msg)
+        raise SdnConnectorError('Impossible to use WIM:\n' + self.error_msg)
 
     def get_all_active_connectivity_services(self):
-        raise WimConnectorError('Impossible to use WIM:\n' + self.error_msg)
+        raise SdnConnectorError('Impossible to use WIM:\n' + self.error_msg)
diff --git a/osm_ro/wim/http_handler.py b/RO/osm_ro/wim/http_handler.py
similarity index 100%
rename from osm_ro/wim/http_handler.py
rename to RO/osm_ro/wim/http_handler.py
diff --git a/RO/osm_ro/wim/openflow_conn.py b/RO/osm_ro/wim/openflow_conn.py
new file mode 100644
index 0000000..7d029f7
--- /dev/null
+++ b/RO/osm_ro/wim/openflow_conn.py
@@ -0,0 +1,464 @@
+##
+# Copyright 2019 Telefonica Investigacion y Desarrollo, S.A.U.
+# All Rights Reserved.
+#
+# 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 logging
+from http import HTTPStatus
+from osm_ro.wim.sdnconn import SdnConnectorBase, SdnConnectorError
+from uuid import uuid4
+
+"""
+Implement an Abstract class 'OpenflowConn' and an engine 'SdnConnectorOpenFlow' used for base class for SDN plugings
+that implements a pro-active opeflow rules.
+"""
+
+__author__ = "Alfonso Tierno"
+__date__ = "2019-11-11"
+
+
+class OpenflowConnException(Exception):
+    """Common and base class Exception for all vimconnector exceptions"""
+    def __init__(self, message, http_code=HTTPStatus.BAD_REQUEST.value):
+        Exception.__init__(self, message)
+        self.http_code = http_code
+
+
+class OpenflowConnConnectionException(OpenflowConnException):
+    """Connectivity error with the VIM"""
+    def __init__(self, message, http_code=HTTPStatus.SERVICE_UNAVAILABLE.value):
+        OpenflowConnException.__init__(self, message, http_code)
+
+
+class OpenflowConnUnexpectedResponse(OpenflowConnException):
+    """Get an wrong response from VIM"""
+    def __init__(self, message, http_code=HTTPStatus.INTERNAL_SERVER_ERROR.value):
+        OpenflowConnException.__init__(self, message, http_code)
+
+
+class OpenflowConnAuthException(OpenflowConnException):
+    """Invalid credentials or authorization to perform this action over the VIM"""
+    def __init__(self, message, http_code=HTTPStatus.UNAUTHORIZED.value):
+        OpenflowConnException.__init__(self, message, http_code)
+
+
+class OpenflowConnNotFoundException(OpenflowConnException):
+    """The item is not found at VIM"""
+    def __init__(self, message, http_code=HTTPStatus.NOT_FOUND.value):
+        OpenflowConnException.__init__(self, message, http_code)
+
+
+class OpenflowConnConflictException(OpenflowConnException):
+    """There is a conflict, e.g. more item found than one"""
+    def __init__(self, message, http_code=HTTPStatus.CONFLICT.value):
+        OpenflowConnException.__init__(self, message, http_code)
+
+
+class OpenflowConnNotSupportedException(OpenflowConnException):
+    """The request is not supported by connector"""
+    def __init__(self, message, http_code=HTTPStatus.SERVICE_UNAVAILABLE.value):
+        OpenflowConnException.__init__(self, message, http_code)
+
+
+class OpenflowConnNotImplemented(OpenflowConnException):
+    """The method is not implemented by the connected"""
+    def __init__(self, message, http_code=HTTPStatus.NOT_IMPLEMENTED.value):
+        OpenflowConnException.__init__(self, message, http_code)
+
+
+class OpenflowConn:
+    """
+    Openflow controller connector abstract implementeation.
+    """
+    def __init__(self, params):
+        self.name = "openflow_conector"
+        self.pp2ofi = {}  # From Physical Port to OpenFlow Index
+        self.ofi2pp = {}  # From OpenFlow Index to Physical Port
+        self.logger = logging.getLogger('openflow_conn')
+        self.logger.setLevel(getattr(logging, params.get("of_debug", "ERROR")))
+
+    def get_of_switches(self):
+        """"
+        Obtain a a list of switches or DPID detected by this controller
+        :return: list length, and a list where each element a tuple pair (DPID, IP address), text_error: if fails
+        """
+        raise OpenflowConnNotImplemented("Should have implemented this")
+
+    def obtain_port_correspondence(self):
+        """
+        Obtain the correspondence between physical and openflow port names
+        :return: dictionary: with physical name as key, openflow name as value, error_text: if fails
+        """
+        raise OpenflowConnNotImplemented("Should have implemented this")
+
+    def get_of_rules(self, translate_of_ports=True):
+        """
+        Obtain the rules inserted at openflow controller
+        :param translate_of_ports: if True it translates ports from openflow index to physical switch name
+        :return: list where each item is a  dictionary with the following content:
+                    priority: rule priority
+                    priority: rule priority
+                    name:         rule name (present also as the master dict key)
+                    ingress_port: match input port of the rule
+                    dst_mac:      match destination mac address of the rule, can be missing or None if not apply
+                    vlan_id:      match vlan tag of the rule, can be missing or None if not apply
+                    actions:      list of actions, composed by a pair tuples:
+                        (vlan, None/int): for stripping/setting a vlan tag
+                        (out, port):      send to this port
+                    switch:       DPID, all
+                 text_error if fails
+        """
+        raise OpenflowConnNotImplemented("Should have implemented this")
+
+    def del_flow(self, flow_name):
+        """
+        Delete all existing rules
+        :param flow_name: flow_name, this is the rule name
+        :return: None if ok, text_error if fails
+        """
+        raise OpenflowConnNotImplemented("Should have implemented this")
+
+    def new_flow(self, data):
+        """
+        Insert a new static rule
+        :param data: dictionary with the following content:
+                priority:     rule priority
+                name:         rule name
+                ingress_port: match input port of the rule
+                dst_mac:      match destination mac address of the rule, missing or None if not apply
+                vlan_id:      match vlan tag of the rule, missing or None if not apply
+                actions:      list of actions, composed by a pair tuples with these posibilities:
+                    ('vlan', None/int): for stripping/setting a vlan tag
+                    ('out', port):      send to this port
+        :return: None if ok, text_error if fails
+        """
+        raise OpenflowConnNotImplemented("Should have implemented this")
+
+    def clear_all_flows(self):
+        """"
+        Delete all existing rules
+        :return: None if ok, text_error if fails
+        """
+        raise OpenflowConnNotImplemented("Should have implemented this")
+
+
+class SdnConnectorOpenFlow(SdnConnectorBase):
+    """
+    This class is the base engine of SDN plugins base on openflow rules
+    """
+    flow_fields = ('priority', 'vlan', 'ingress_port', 'actions', 'dst_mac', 'src_mac', 'net_id')
+
+    def __init__(self, wim, wim_account, config=None, logger=None, of_connector=None):
+        self.logger = logger or logging.getLogger('openmano.sdnconn.openflow')
+        self.of_connector = of_connector
+        self.of_controller_nets_with_same_vlan = config.get("of_controller_nets_with_same_vlan", False)
+
+    def check_credentials(self):
+        try:
+            self.openflow_conn.obtain_port_correspondence()
+        except OpenflowConnException as e:
+            raise SdnConnectorError(e, http_code=e.http_code)
+
+    def get_connectivity_service_status(self, service_uuid, conn_info=None):
+        conn_info = conn_info or {}
+        return {
+            "sdn_status": conn_info.get("status", "ERROR"),
+            "error_msg": conn_info.get("error_msg", "Variable conn_info not provided"),
+        }
+        # TODO check rules connectirng to of_connector
+
+    def create_connectivity_service(self, service_type, connection_points, **kwargs):
+        net_id = str(uuid4())
+        ports = []
+        for cp in connection_points:
+            port = {
+                "uuid": cp["service_endpoint_id"],
+                "vlan": cp.get("service_endpoint_encapsulation_info", {}).get("vlan"),
+                "mac": cp.get("service_endpoint_encapsulation_info", {}).get("mac"),
+                "switch_port": cp.get("service_endpoint_encapsulation_info", {}).get("switch_port"),
+            }
+            ports.append(port)
+        try:
+            created_items = self._set_openflow_rules(service_type, net_id, ports, created_items=None)
+            return net_id, created_items
+        except (SdnConnectorError, OpenflowConnException) as e:
+            raise SdnConnectorError(e, http_code=e.http_code)
+
+    def delete_connectivity_service(self, service_uuid, conn_info=None):
+        try:
+            service_type = "ELAN"
+            ports = []
+            self._set_openflow_rules(service_type, service_uuid, ports, created_items=conn_info)
+            return None
+        except (SdnConnectorError, OpenflowConnException) as e:
+            raise SdnConnectorError(e, http_code=e.http_code)
+
+    def edit_connectivity_service(self, service_uuid, conn_info=None, connection_points=None, **kwargs):
+        ports = []
+        for cp in connection_points:
+            port = {
+                "uuid": cp["service_endpoint_id"],
+                "vlan": cp.get("service_endpoint_encapsulation_info", {}).get("vlan"),
+                "mac": cp.get("service_endpoint_encapsulation_info", {}).get("mac"),
+                "switch_port": cp.get("service_endpoint_encapsulation_info", {}).get("switch_port"),
+            }
+            ports.append(port)
+        service_type = "ELAN"  # TODO. Store at conn_info for later use
+        try:
+            created_items = self._set_openflow_rules(service_type, service_uuid, ports, created_items=conn_info)
+            return created_items
+        except (SdnConnectorError, OpenflowConnException) as e:
+            raise SdnConnectorError(e, http_code=e.http_code)
+
+    def clear_all_connectivity_services(self):
+        """Delete all WAN Links corresponding to a WIM"""
+        pass
+
+    def get_all_active_connectivity_services(self):
+        """Provide information about all active connections provisioned by a
+        WIM
+        """
+        pass
+
+    def _set_openflow_rules(self, net_type, net_id, ports, created_items=None):
+        ifaces_nb = len(ports)
+        if not created_items:
+            created_items = {"status": None, "error_msg": None, "installed_rules_ids": []}
+        rules_to_delete = created_items.get("installed_rules_ids") or []
+        new_installed_rules_ids = []
+        error_list = []
+
+        try:
+            step = "Checking ports and network type compatibility"
+            if ifaces_nb < 2:
+                pass
+            elif net_type == 'ELINE':
+                if ifaces_nb > 2:
+                    raise SdnConnectorError("'ELINE' type network cannot connect {} interfaces, only 2".format(
+                        ifaces_nb))
+            elif net_type == 'ELAN':
+                if ifaces_nb > 2 and self.of_controller_nets_with_same_vlan:
+                    # check all ports are VLAN (tagged) or none
+                    vlan_tags = []
+                    for port in ports:
+                        if port["vlan"] not in vlan_tags:
+                            vlan_tags.append(port["vlan"])
+                    if len(vlan_tags) > 1:
+                        raise SdnConnectorError("This pluging cannot connect ports with diferent VLAN tags when flag "
+                                                "'of_controller_nets_with_same_vlan' is active")
+            else:
+                raise SdnConnectorError('Only ELINE or ELAN network types are supported for openflow')
+
+            # Get the existing flows at openflow controller
+            step = "Getting installed openflow rules"
+            existing_flows = self.of_connector.get_of_rules()
+            existing_flows_ids = [flow["name"] for flow in existing_flows]
+
+            # calculate new flows to be inserted
+            step = "Compute needed openflow rules"
+            new_flows = self._compute_net_flows(net_id, ports)
+
+            name_index = 0
+            for flow in new_flows:
+                # 1 check if an equal flow is already present
+                index = self._check_flow_already_present(flow, existing_flows)
+                if index >= 0:
+                    flow_id = existing_flows[index]["name"]
+                    self.logger.debug("Skipping already present flow %s", str(flow))
+                else:
+                    # 2 look for a non used name
+                    flow_name = flow["net_id"] + "." + str(name_index)
+                    while flow_name in existing_flows_ids:
+                        name_index += 1
+                        flow_name = flow["net_id"] + "." + str(name_index)
+                    flow['name'] = flow_name
+                    # 3 insert at openflow
+                    try:
+                        self.of_connector.new_flow(flow)
+                        flow_id = flow["name"]
+                        existing_flows_ids.append(flow_id)
+                    except OpenflowConnException as e:
+                        flow_id = None
+                        error_list.append("Cannot create rule for ingress_port={}, dst_mac={}: {}"
+                                          .format(flow["ingress_port"], flow["dst_mac"], e))
+
+                # 4 insert at database
+                if flow_id:
+                    new_installed_rules_ids.append(flow_id)
+                    if flow_id in rules_to_delete:
+                        rules_to_delete.remove(flow_id)
+
+            # delete not needed old flows from openflow
+            for flow_id in rules_to_delete:
+                # Delete flow
+                try:
+                    self.of_connector.del_flow(flow_id)
+                except OpenflowConnNotFoundException:
+                    pass
+                except OpenflowConnException as e:
+                    error_text = "Cannot remove rule '{}': {}".format(flow['name'], e)
+                    error_list.append(error_text)
+                    self.logger.error(error_text)
+            created_items["installed_rules_ids"] = new_installed_rules_ids
+            if error_list:
+                created_items["error_msg"] = ";".join(error_list)[:1000]
+                created_items["error_msg"] = "ERROR"
+            else:
+                created_items["error_msg"] = None
+                created_items["status"] = "ACTIVE"
+            return created_items
+        except (SdnConnectorError, OpenflowConnException) as e:
+            raise SdnConnectorError("Error while {}: {}".format(step, e)) from e
+        except Exception as e:
+            self.logger.critical(error_text, exc_info=True)
+            raise SdnConnectorError("Error while {}: {}".format(step, e))
+
+    def _compute_net_flows(self, net_id, ports):
+        new_flows = []
+        new_broadcast_flows = {}
+        nb_ports = len(ports)
+
+        # Check switch_port information is right
+        for port in ports:
+            nb_ports += 1
+            if str(port['switch_port']) not in self.of_connector.pp2ofi:
+                raise SdnConnectorError("switch port name '{}' is not valid for the openflow controller".
+                                        format(port['switch_port']))
+        priority = 1000  # 1100
+
+        for src_port in ports:
+            # if src_port.get("groups")
+            vlan_in = src_port['vlan']
+
+            # BROADCAST:
+            broadcast_key = src_port['uuid'] + "." + str(vlan_in)
+            if broadcast_key in new_broadcast_flows:
+                flow_broadcast = new_broadcast_flows[broadcast_key]
+            else:
+                flow_broadcast = {'priority': priority,
+                                  'net_id': net_id,
+                                  'dst_mac': 'ff:ff:ff:ff:ff:ff',
+                                  "ingress_port": str(src_port['switch_port']),
+                                  'vlan_id': vlan_in,
+                                  'actions': []
+                                  }
+                new_broadcast_flows[broadcast_key] = flow_broadcast
+                if vlan_in is not None:
+                    flow_broadcast['vlan_id'] = str(vlan_in)
+
+            for dst_port in ports:
+                vlan_out = dst_port['vlan']
+                if src_port['switch_port'] == dst_port['switch_port'] and vlan_in == vlan_out:
+                    continue
+                flow = {
+                    "priority": priority,
+                    'net_id': net_id,
+                    "ingress_port": str(src_port['switch_port']),
+                    'vlan_id': vlan_in,
+                    'actions': []
+                }
+                # allow that one port have no mac
+                if dst_port['mac'] is None or nb_ports == 2:  # point to point or nets with 2 elements
+                    flow['priority'] = priority - 5  # less priority
+                else:
+                    flow['dst_mac'] = str(dst_port['mac'])
+
+                if vlan_out is None:
+                    if vlan_in:
+                        flow['actions'].append(('vlan', None))
+                else:
+                    flow['actions'].append(('vlan', vlan_out))
+                flow['actions'].append(('out', str(dst_port['switch_port'])))
+
+                if self._check_flow_already_present(flow, new_flows) >= 0:
+                    self.logger.debug("Skipping repeated flow '%s'", str(flow))
+                    continue
+
+                new_flows.append(flow)
+
+                # BROADCAST:
+                if nb_ports <= 2:  # point to multipoint or nets with more than 2 elements
+                    continue
+                out = (vlan_out, str(dst_port['switch_port']))
+                if out not in flow_broadcast['actions']:
+                    flow_broadcast['actions'].append(out)
+
+        # BROADCAST
+        for flow_broadcast in new_broadcast_flows.values():
+            if len(flow_broadcast['actions']) == 0:
+                continue  # nothing to do, skip
+            flow_broadcast['actions'].sort()
+            if 'vlan_id' in flow_broadcast:
+                previous_vlan = 0  # indicates that a packet contains a vlan, and the vlan
+            else:
+                previous_vlan = None
+            final_actions = []
+            action_number = 0
+            for action in flow_broadcast['actions']:
+                if action[0] != previous_vlan:
+                    final_actions.append(('vlan', action[0]))
+                    previous_vlan = action[0]
+                    if self.of_controller_nets_with_same_vlan and action_number:
+                        raise SdnConnectorError("Cannot interconnect different vlan tags in a network when flag "
+                                                "'of_controller_nets_with_same_vlan' is True.")
+                    action_number += 1
+                final_actions.append(('out', action[1]))
+            flow_broadcast['actions'] = final_actions
+
+            if self._check_flow_already_present(flow_broadcast, new_flows) >= 0:
+                self.logger.debug("Skipping repeated flow '%s'", str(flow_broadcast))
+                continue
+
+            new_flows.append(flow_broadcast)
+
+        # UNIFY openflow rules with the same input port and vlan and the same output actions
+        # These flows differ at the dst_mac; and they are unified by not filtering by dst_mac
+        # this can happen if there is only two ports. It is converted to a point to point connection
+        flow_dict = {}  # use as key vlan_id+ingress_port and as value the list of flows matching these values
+        for flow in new_flows:
+            key = str(flow.get("vlan_id")) + ":" + flow["ingress_port"]
+            if key in flow_dict:
+                flow_dict[key].append(flow)
+            else:
+                flow_dict[key] = [flow]
+        new_flows2 = []
+        for flow_list in flow_dict.values():
+            convert2ptp = False
+            if len(flow_list) >= 2:
+                convert2ptp = True
+                for f in flow_list:
+                    if f['actions'] != flow_list[0]['actions']:
+                        convert2ptp = False
+                        break
+            if convert2ptp:  # add only one unified rule without dst_mac
+                self.logger.debug("Convert flow rules to NON mac dst_address " + str(flow_list))
+                flow_list[0].pop('dst_mac')
+                flow_list[0]["priority"] -= 5
+                new_flows2.append(flow_list[0])
+            else:  # add all the rules
+                new_flows2 += flow_list
+        return new_flows2
+
+    def _check_flow_already_present(self, new_flow, flow_list):
+        '''check if the same flow is already present in the flow list
+        The flow is repeated if all the fields, apart from name, are equal
+        Return the index of matching flow, -1 if not match'''
+        for index, flow in enumerate(flow_list):
+            for f in self.flow_fields:
+                if flow.get(f) != new_flow.get(f):
+                    break
+            else:
+                return index
+        return -1
diff --git a/osm_ro/wim/persistence.py b/RO/osm_ro/wim/persistence.py
similarity index 98%
rename from osm_ro/wim/persistence.py
rename to RO/osm_ro/wim/persistence.py
index 74f7dc6..32a46b3 100644
--- a/osm_ro/wim/persistence.py
+++ b/RO/osm_ro/wim/persistence.py
@@ -44,12 +44,10 @@
 from hashlib import sha1
 from itertools import groupby
 from operator import itemgetter
-from sys import exc_info
+# from sys import exc_info
 # from time import time
 from uuid import uuid1 as generate_uuid
 
-from six import reraise
-
 import yaml
 
 from ..utils import (
@@ -364,6 +362,7 @@
     def get_wim_accounts(self, **kwargs):
         """Retrieve all the accounts from the database"""
         kwargs.setdefault('postprocess', _postprocess_wim_account)
+        kwargs.setdefault('WHERE', {"sdn": "false"})
         return self.query(FROM=_WIM_ACCOUNT_JOIN, **kwargs)
 
     def get_wim_account(self, uuid_or_name, **kwargs):
@@ -388,8 +387,7 @@
             if all([msg in error_msg
                     for msg in ("already in use", "'wim_nfvo_tenant'")]):
                 ex = WimAndTenantAlreadyAttached(wim_id, nfvo_tenant_id)
-                reraise(ex.__class__, ex, exc_info()[2])
-
+                raise ex from db_exception
             raise
 
     def create_wim_account(self, wim, tenant, properties):
@@ -526,11 +524,11 @@
             self.logger.exception(old_exception)
             ex = InvalidParameters(
                 "The mapping must contain the "
-                "'pop_switch_dpid', 'pop_switch_port',  and "
+                "'device_id', 'device_interface_id',  and "
                 "wan_service_mapping_info: "
                 "('wan_switch_dpid' and 'wan_switch_port') or "
                 "'wan_service_endpoint_id}'")
-            reraise(ex.__class__, ex, exc_info()[2])
+            raise ex from old_exception
 
         return properties
 
@@ -730,7 +728,7 @@
         kwargs.setdefault('error_if_none', False)
 
         criteria_fields = ('uuid', 'instance_scenario_id', 'sce_net_id',
-                           'wim_id', 'wim_account_id')
+                           'wim_id', 'wim_account_id', 'sdn')
         criteria = remove_none_items(filter_dict_keys(kwargs, criteria_fields))
         kwargs = filter_out_dict_keys(kwargs, criteria_fields)
 
@@ -929,7 +927,7 @@
     if not(isinstance(record, dict) and fields):
         return record
 
-    keys = record.iterkeys()
+    keys = list(record.keys())
     keys = (k for k in keys for f in fields if k == f or k.endswith('.'+f))
 
     return merge_dicts(record, {k: '********' for k in keys if record[k]})
@@ -940,7 +938,7 @@
     """Unserialize fields that where stored in the database as a serialized
     YAML (or JSON)
     """
-    keys = record.iterkeys()
+    keys = list(record.keys())
     keys = (k for k in keys for f in fields if k == f or k.endswith('.'+f))
 
     return merge_dicts(record, {
@@ -951,7 +949,7 @@
 
 def serialize_fields(record, fields=_SERIALIZED_FIELDS):
     """Serialize fields to be stored in the database as YAML"""
-    keys = record.iterkeys()
+    keys = list(record.keys())
     keys = (k for k in keys for f in fields if k == f or k.endswith('.'+f))
 
     return merge_dicts(record, {
diff --git a/osm_ro/wim/schemas.py b/RO/osm_ro/wim/schemas.py
similarity index 81%
rename from osm_ro/wim/schemas.py
rename to RO/osm_ro/wim/schemas.py
index 101bcb1..8f9653b 100644
--- a/osm_ro/wim/schemas.py
+++ b/RO/osm_ro/wim/schemas.py
@@ -69,36 +69,21 @@
                 "items": {
                     "type": "object",
                     "properties": {
-                        "pop_switch_dpid": dpid_type,
-                        "pop_switch_port": port_type,
-                        "wan_service_endpoint_id": name_schema,
-                        "wan_service_mapping_info": {
+                        "device_id": nameshort_schema,
+                        "device_interface_id": nameshort_schema,
+                        "service_endpoint_id": name_schema,
+                        "switch_dpid": dpid_type,
+                        "switch_port": port_type,
+                        "service_mapping_info": {
                             "type": "object",
                             "properties": {
                                 "mapping_type": name_schema,
-                                "wan_switch_dpid": dpid_type,
-                                "wan_switch_port": port_type
                             },
                             "additionalProperties": True,
                             "required": ["mapping_type"]
                         }
                     },
-                    "anyOf": [
-                        {
-                            "required": [
-                                "pop_switch_dpid",
-                                "pop_switch_port",
-                                "wan_service_endpoint_id"
-                            ]
-                        },
-                        {
-                            "required": [
-                                "pop_switch_dpid",
-                                "pop_switch_port",
-                                "wan_service_mapping_info"
-                            ]
-                        }
-                    ]
+                    "required": ["service_endpoint_id"]
                 }
             }
         },
@@ -111,7 +96,7 @@
     "description": description_schema,
     "type": {
         "type": "string",
-        "enum": ["tapi", "onos", "odl", "dynpac", "fake"]
+        # "enum": ["tapi", "onos", "odl", "dynpac", "fake"]
     },
     "wim_url": description_schema,
     "config": {
diff --git a/RO/osm_ro/wim/sdnconn.py b/RO/osm_ro/wim/sdnconn.py
new file mode 100644
index 0000000..46649ce
--- /dev/null
+++ b/RO/osm_ro/wim/sdnconn.py
@@ -0,0 +1,238 @@
+# -*- coding: utf-8 -*-
+##
+# Copyright 2018 University of Bristol - High Performance Networks Research
+# Group
+# All Rights Reserved.
+#
+# Contributors: Anderson Bravalheri, Dimitrios Gkounis, Abubakar Siddique
+# Muqaddas, Navdeep Uniyal, Reza Nejabati and Dimitra Simeonidou
+#
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: <highperformance-networks@bristol.ac.uk>
+#
+# Neither the name of the University of Bristol nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# This work has been performed in the context of DCMS UK 5G Testbeds
+# & Trials Programme and in the framework of the Metro-Haul project -
+# funded by the European Commission under Grant number 761727 through the
+# Horizon 2020 and 5G-PPP programmes.
+##
+"""The SDN connector is responsible for establishing both wide area network connectivity (WIM)
+and intranet SDN connectivity.
+
+It receives information from ports to be connected .
+"""
+import logging
+
+from ..http_tools.errors import HttpMappedError
+
+
+class SdnConnectorError(HttpMappedError):
+    """Base Exception for all connector related errors
+        provide the parameter 'http_code' (int) with the error code:
+            Bad_Request = 400
+            Unauthorized = 401  (e.g. credentials are not valid)
+            Not_Found = 404    (e.g. try to edit or delete a non existing connectivity service)
+            Forbidden = 403
+            Method_Not_Allowed = 405
+            Not_Acceptable = 406
+            Request_Timeout = 408  (e.g timeout reaching server, or cannot reach the server)
+            Conflict = 409
+            Service_Unavailable = 503
+            Internal_Server_Error = 500
+    """
+
+
+class SdnConnectorBase(object):
+    """Abstract base class for all the SDN connectors
+
+    Arguments:
+        wim (dict): WIM record, as stored in the database
+        wim_account (dict): WIM account record, as stored in the database
+        config
+    The arguments of the constructor are converted to object attributes.
+    An extra property, ``service_endpoint_mapping`` is created from ``config``.
+    """
+    def __init__(self, wim, wim_account, config=None, logger=None):
+        """
+
+        :param wim: (dict). Contains among others 'wim_url'
+        :param wim_account: (dict). Contains among others 'uuid' (internal id), 'name',
+            'sdn' (True if is intended for SDN-assist or False if intended for WIM), 'user', 'password'.
+        :param config: (dict or None): Particular information of plugin. These keys if present have a common meaning:
+            'mapping_not_needed': (bool) False by default or if missing, indicates that mapping is not needed.
+            'service_endpoint_mapping': (list) provides the internal endpoint mapping. The meaning is:
+                KEY 	    	        meaning for WIM		        meaning for SDN assist
+                --------                --------                    --------
+                device_id		        pop_switch_dpid		        compute_id
+                device_interface_id		pop_switch_port		        compute_pci_address
+                service_endpoint_id	    wan_service_endpoint_id     SDN_service_endpoint_id
+                service_mapping_info	wan_service_mapping_info    SDN_service_mapping_info
+                    contains extra information if needed. Text in Yaml format
+                switch_dpid		        wan_switch_dpid		        SDN_switch_dpid
+                switch_port		        wan_switch_port		        SDN_switch_port
+                datacenter_id           vim_account                 vim_account
+                id: (internal, do not use)
+                wim_id: (internal, do not use)
+        :param logger (logging.Logger): optional logger object. If none is passed 'openmano.sdn.sdnconn' is used.
+        """
+        self.logger = logger or logging.getLogger('openmano.sdn.sdnconn')
+
+        self.wim = wim
+        self.wim_account = wim_account
+        self.config = config or {}
+        self.service_endpoint_mapping = (
+            self.config.get('service_endpoint_mapping', []))
+
+    def check_credentials(self):
+        """Check if the connector itself can access the SDN/WIM with the provided url (wim.wim_url),
+            user (wim_account.user), and password (wim_account.password)
+
+        Raises:
+            SdnConnectorError: Issues regarding authorization, access to
+                external URLs, etc are detected.
+        """
+        raise NotImplementedError
+
+    def get_connectivity_service_status(self, service_uuid, conn_info=None):
+        """Monitor the status of the connectivity service established
+
+        Arguments:
+            service_uuid (str): UUID of the connectivity service
+            conn_info (dict or None): Information returned by the connector
+                during the service creation/edition and subsequently stored in
+                the database.
+
+        Returns:
+            dict: JSON/YAML-serializable dict that contains a mandatory key
+                ``sdn_status`` associated with one of the following values::
+
+                    {'sdn_status': 'ACTIVE'}
+                        # The service is up and running.
+
+                    {'sdn_status': 'INACTIVE'}
+                        # The service was created, but the connector
+                        # cannot determine yet if connectivity exists
+                        # (ideally, the caller needs to wait and check again).
+
+                    {'sdn_status': 'DOWN'}
+                        # Connection was previously established,
+                        # but an error/failure was detected.
+
+                    {'sdn_status': 'ERROR'}
+                        # An error occurred when trying to create the service/
+                        # establish the connectivity.
+
+                    {'sdn_status': 'BUILD'}
+                        # Still trying to create the service, the caller
+                        # needs to wait and check again.
+
+                Additionally ``error_msg``(**str**) and ``sdn_info``(**dict**)
+                keys can be used to provide additional status explanation or
+                new information available for the connectivity service.
+        """
+        raise NotImplementedError
+
+    def create_connectivity_service(self, service_type, connection_points, **kwargs):
+        """
+        Stablish SDN/WAN connectivity between the endpoints
+        :param service_type: (str): ``ELINE`` (L2), ``ELAN`` (L2), ``ETREE`` (L2), ``L3``.
+        :param connection_points:  (list): each point corresponds to
+            an entry point to be connected. For WIM: from the DC to the transport network.
+            For SDN: Compute/PCI to the transport network. One
+            connection point serves to identify the specific access and
+            some other service parameters, such as encapsulation type.
+            Each item of the list is a dict with:
+                "service_endpoint_id": (str)(uuid)  Same meaning that for 'service_endpoint_mapping' (see __init__)
+                    In case the config attribute mapping_not_needed is True, this value is not relevant. In this case
+                    it will contain the string "device_id:device_interface_id"
+                "service_endpoint_encapsulation_type": None, "dot1q", ...
+                "service_endpoint_encapsulation_info": (dict) with:
+                    "vlan": ..., (int, present if encapsulation is dot1q)
+                    "vni": ... (int, present if encapsulation is vxlan),
+                    "peers": [(ipv4_1), (ipv4_2)] (present if encapsulation is vxlan)
+                    "mac": ...
+                    "device_id": ..., same meaning that for 'service_endpoint_mapping' (see __init__)
+                    "device_interface_id": same meaning that for 'service_endpoint_mapping' (see __init__)
+                    "switch_dpid": ..., present if mapping has been found for this device_id,device_interface_id
+                    "swith_port": ... present if mapping has been found for this device_id,device_interface_id
+                    "service_mapping_info": present if mapping has been found for this device_id,device_interface_id
+        :param kwargs: For future versions:
+            bandwidth (int): value in kilobytes
+            latency (int): value in milliseconds
+            Other QoS might be passed as keyword arguments.
+        :return: tuple: ``(service_id, conn_info)`` containing:
+            - *service_uuid* (str): UUID of the established connectivity service
+            - *conn_info* (dict or None): Information to be stored at the database (or ``None``).
+                This information will be provided to the :meth:`~.edit_connectivity_service` and :obj:`~.delete`.
+                **MUST** be JSON/YAML-serializable (plain data structures).
+        :raises: SdnConnectorException: In case of error. Nothing should be created in this case.
+            Provide the parameter http_code
+        """
+        raise NotImplementedError
+
+    def delete_connectivity_service(self, service_uuid, conn_info=None):
+        """
+        Disconnect multi-site endpoints previously connected
+
+        :param service_uuid: The one returned by create_connectivity_service
+        :param conn_info: The one returned by last call to 'create_connectivity_service' or 'edit_connectivity_service'
+            if they do not return None
+        :return: None
+        :raises: SdnConnectorException: In case of error. The parameter http_code must be filled
+        """
+        raise NotImplementedError
+
+    def edit_connectivity_service(self, service_uuid, conn_info=None, connection_points=None, **kwargs):
+        """ Change an existing connectivity service.
+
+        This method's arguments and return value follow the same convention as
+        :meth:`~.create_connectivity_service`.
+
+        :param service_uuid: UUID of the connectivity service.
+        :param conn_info: (dict or None): Information previously returned by last call to create_connectivity_service
+            or edit_connectivity_service
+        :param connection_points: (list): If provided, the old list of connection points will be replaced.
+        :param kwargs: Same meaning that create_connectivity_service
+        :return: dict or None: Information to be updated and stored at the database.
+                When ``None`` is returned, no information should be changed.
+                When an empty dict is returned, the database record will be deleted.
+                **MUST** be JSON/YAML-serializable (plain data structures).
+        Raises:
+            SdnConnectorException: In case of error.
+        """
+
+    def clear_all_connectivity_services(self):
+        """Delete all WAN Links in a WIM.
+
+        This method is intended for debugging only, and should delete all the
+        connections controlled by the WIM/SDN, not only the  connections that
+        a specific RO is aware of.
+
+        Raises:
+            SdnConnectorException: In case of error.
+        """
+        raise NotImplementedError
+
+    def get_all_active_connectivity_services(self):
+        """Provide information about all active connections provisioned by a
+        WIM.
+
+        Raises:
+            SdnConnectorException: In case of error.
+        """
+        raise NotImplementedError
diff --git a/RO/osm_ro/wim/tests/__init__.py b/RO/osm_ro/wim/tests/__init__.py
new file mode 100644
index 0000000..7284a2b
--- /dev/null
+++ b/RO/osm_ro/wim/tests/__init__.py
@@ -0,0 +1,13 @@
+##
+# 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.
+##
diff --git a/osm_ro/wim/tests/fixtures.py b/RO/osm_ro/wim/tests/fixtures.py
similarity index 94%
rename from osm_ro/wim/tests/fixtures.py
rename to RO/osm_ro/wim/tests/fixtures.py
index c39e9d7..b37cc13 100644
--- a/osm_ro/wim/tests/fixtures.py
+++ b/RO/osm_ro/wim/tests/fixtures.py
@@ -36,12 +36,9 @@
 from __future__ import unicode_literals
 
 import json
-from itertools import izip
 from time import time
 from textwrap import wrap
 
-from six.moves import range
-
 from ...tests.db_helpers import uuid, sha1
 
 NUM_WIMS = 3
@@ -101,8 +98,8 @@
                 'provider:physical_network': 'provider',
                 'encapsulation_type': 'vlan'},
                 'vim_external_port':
-                dict(izip(('switch', 'port'),
-                          _datacenter_to_switch_port(identifier)))}
+                dict(zip(('switch', 'port'),
+                         _datacenter_to_switch_port(identifier)))}
         ]})
 
     return {'uuid': uuid('dc%d' % identifier),
@@ -147,13 +144,13 @@
 
     return {'wim_id': uuid('wim%d' % wim),
             'datacenter_id': uuid('dc%d' % datacenter),
-            'pop_switch_dpid': pop_dpid,
-            'pop_switch_port': (str(pop_port) if pop_port else
-                                str(int(datacenter) + int(wim) + 1)),
+            'device_id': pop_dpid,
+            'device_interface_id': (str(pop_port) if pop_port else
+                                    str(int(datacenter) + int(wim) + 1)),
             # ^  Datacenter router have one port managed by each WIM
-            'wan_service_endpoint_id': id_,
+            'service_endpoint_id': id_,
             # ^  WIM managed router have one port connected to each DC
-            'wan_service_mapping_info': json.dumps(mapping_info)}
+            'service_mapping_info': json.dumps(mapping_info)}
 
 
 def processed_port_mapping(wim, datacenter,
@@ -167,11 +164,11 @@
         'wim_id': uuid('wim%d' % wim),
         'datacenter_id': uuid('dc%d' % datacenter),
         'pop_wan_mappings': [
-            {'pop_switch_dpid': pop_dpid,
-             'pop_switch_port': wim + 1 + i,
-             'wan_service_endpoint_id':
+            {'device_id': pop_dpid,
+             'device_interface_id': wim + 1 + i,
+             'service_endpoint_id':
                  sha1('dpid-port|%s|%d' % (wan_dpid, datacenter + 1 + i)),
-             'wan_service_mapping_info': {
+             'service_mapping_info': {
                  'mapping_type': 'dpid-port',
                  'wan_switch_dpid': wan_dpid,
                  'wan_switch_port': datacenter + 1 + i}}
diff --git a/osm_ro/wim/tests/test_actions.py b/RO/osm_ro/wim/tests/test_actions.py
similarity index 97%
rename from osm_ro/wim/tests/test_actions.py
rename to RO/osm_ro/wim/tests/test_actions.py
index cee3c96..ba66fbc 100644
--- a/osm_ro/wim/tests/test_actions.py
+++ b/RO/osm_ro/wim/tests/test_actions.py
@@ -33,13 +33,13 @@
 ##
 # pylint: disable=E1101
 
-from __future__ import unicode_literals, print_function
+# from __future__ import unicode_literals, print_function
 
 import json
 import unittest
 from time import time
 
-from mock import MagicMock, patch
+from unittest.mock import MagicMock, patch
 
 from . import fixtures as eg
 from ...tests.db_helpers import (
@@ -49,7 +49,7 @@
 )
 from ..persistence import WimPersistence, preprocess_record
 from ..wan_link_actions import WanLinkCreate, WanLinkDelete
-from ..wimconn import WimConnectorError
+from ..sdnconn import SdnConnectorError
 
 
 class TestActionsWithDb(TestCaseWithDatabasePerTest):
@@ -192,7 +192,7 @@
 
         # If the connector raises an error
         with patch.object(self.connector, 'create_connectivity_service',
-                          MagicMock(side_effect=WimConnectorError('foobar'))):
+                          MagicMock(side_effect=SdnConnectorError('foobar'))):
             # When we try to process a CREATE action that refers to the same
             # instance_scenario_id and sce_net_id
             action.process(self.connector, self.persist, self.ovim)
@@ -219,8 +219,8 @@
         port_mappings = next(r['wim_port_mappings']
                              for r in db_state if 'wim_port_mappings' in r)
         for mapping in port_mappings:
-            mapping['pop_switch_dpid'] = switch
-            mapping['pop_switch_port'] = port
+            mapping['device_id'] = switch
+            mapping['device_interface_id'] = port
 
         instance_action = eg.instance_action(action_id='ACTION-000')
         instance_nets = eg.instance_nets(num_datacenters=2, num_links=1,
@@ -294,7 +294,7 @@
 
         connector_patch = patch.object(
             self.connector, 'create_connectivity_service',
-            MagicMock(side_effect=WimConnectorError('foobar')))
+            MagicMock(side_effect=SdnConnectorError('foobar')))
 
         # If the connector throws an error
         with connector_patch, ovim_patch:
diff --git a/osm_ro/wim/tests/test_engine.py b/RO/osm_ro/wim/tests/test_engine.py
similarity index 98%
rename from osm_ro/wim/tests/test_engine.py
rename to RO/osm_ro/wim/tests/test_engine.py
index 9bb7bca..d518123 100644
--- a/osm_ro/wim/tests/test_engine.py
+++ b/RO/osm_ro/wim/tests/test_engine.py
@@ -32,11 +32,9 @@
 # Horizon 2020 and 5G-PPP programmes.
 ##
 
-from __future__ import unicode_literals
-
 import unittest
 
-from mock import MagicMock
+from unittest.mock import MagicMock
 
 from . import fixtures as eg
 from ...tests.db_helpers import TestCaseWithDatabasePerTest, uuid
diff --git a/osm_ro/wim/tests/test_http_handler.py b/RO/osm_ro/wim/tests/test_http_handler.py
similarity index 96%
rename from osm_ro/wim/tests/test_http_handler.py
rename to RO/osm_ro/wim/tests/test_http_handler.py
index 428b1ce..ab3e2d0 100644
--- a/osm_ro/wim/tests/test_http_handler.py
+++ b/RO/osm_ro/wim/tests/test_http_handler.py
@@ -32,12 +32,10 @@
 # Horizon 2020 and 5G-PPP programmes.
 ##
 
-from __future__ import unicode_literals
-
 import unittest
 
 import bottle
-from mock import MagicMock, patch
+from unittest.mock import MagicMock, patch
 from webtest import TestApp
 
 from . import fixtures as eg  # "examples"
@@ -149,9 +147,9 @@
                     config={'wim_port_mapping': [{
                         'datacenter_name': 'dc0',
                         'pop_wan_mappings': [{
-                            'pop_switch_dpid': '00:AA:11:BB:22:CC:33:DD',
-                            'pop_switch_port': 1,
-                            'wan_service_mapping_info': {
+                            'device_id': '00:AA:11:BB:22:CC:33:DD',
+                            'device_interface_id': 1,
+                            'service_mapping_info': {
                                 'mapping_type': 'dpid-port',
                                 'wan_switch_dpid': 'BB:BB:BB:BB:BB:BB:BB:0A',
                                 'wan_switch_port': 1
@@ -172,7 +170,7 @@
         mappings = response.json['wim']['config']['wim_port_mapping']
         self.assertEqual(len(mappings), 1)
         self.assertEqual(
-            mappings[0]['pop_wan_mappings'][0]['pop_switch_dpid'],
+            mappings[0]['pop_wan_mappings'][0]['device_id'],
             '00:AA:11:BB:22:CC:33:DD')
 
     def test_delete_wim(self):
@@ -226,9 +224,9 @@
                     config={'wim_port_mapping': [{
                         'datacenter_name': 'dc0',
                         'pop_wan_mappings': [{
-                            'pop_switch_dpid': 'AA:AA:AA:AA:AA:AA:AA:01',
-                            'pop_switch_port': 1,
-                            'wan_service_mapping_info': {
+                            'device_id': 'AA:AA:AA:AA:AA:AA:AA:01',
+                            'device_interface_id': 1,
+                            'service_mapping_info': {
                                 'mapping_type': 'dpid-port',
                                 'wan_switch_dpid': 'BB:BB:BB:BB:BB:BB:BB:01',
                                 'wan_switch_port': 1
@@ -525,9 +523,9 @@
             {'wim_port_mapping': [{
                 'datacenter_name': 'dc888',
                 'pop_wan_mappings': [
-                    {'pop_switch_dpid': 'AA:AA:AA:AA:AA:AA:AA:AA',
-                     'pop_switch_port': 1,
-                     'wan_service_mapping_info': {
+                    {'device_id': 'AA:AA:AA:AA:AA:AA:AA:AA',
+                     'device_interface_id': 1,
+                     'service_mapping_info': {
                          'mapping_type': 'dpid-port',
                          'wan_switch_dpid': 'BB:BB:BB:BB:BB:BB:BB:BB',
                          'wan_switch_port': 1
diff --git a/osm_ro/wim/tests/test_persistence.py b/RO/osm_ro/wim/tests/test_persistence.py
similarity index 98%
rename from osm_ro/wim/tests/test_persistence.py
rename to RO/osm_ro/wim/tests/test_persistence.py
index e3e6cf6..ecca4fa 100644
--- a/osm_ro/wim/tests/test_persistence.py
+++ b/RO/osm_ro/wim/tests/test_persistence.py
@@ -32,13 +32,8 @@
 # Horizon 2020 and 5G-PPP programmes.
 ##
 
-from __future__ import unicode_literals
-
 import unittest
 from itertools import chain
-from types import StringType
-
-from six.moves import range
 
 from . import fixtures as eg
 from ...tests.db_helpers import (
@@ -75,7 +70,7 @@
         }
         result = serialize_fields(example, fields=('config', 'info'))
         for field in 'config', 'nested.info':
-            self.assertIsInstance(result[field], StringType)
+            self.assertIsInstance(result[field], str)
         self.assertIs(result['nested.config'], None)
 
     def test_unserialize_fields(self):
diff --git a/osm_ro/wim/tests/test_wim_thread.py b/RO/osm_ro/wim/tests/test_wim_thread.py
similarity index 98%
rename from osm_ro/wim/tests/test_wim_thread.py
rename to RO/osm_ro/wim/tests/test_wim_thread.py
index 6d61848..7ad66c2 100644
--- a/osm_ro/wim/tests/test_wim_thread.py
+++ b/RO/osm_ro/wim/tests/test_wim_thread.py
@@ -32,8 +32,6 @@
 # Horizon 2020 and 5G-PPP programmes.
 ##
 
-from __future__ import unicode_literals, print_function
-
 import unittest
 from difflib import unified_diff
 from operator import itemgetter
@@ -41,7 +39,7 @@
 
 import json
 
-from mock import MagicMock, patch
+from unittest.mock import MagicMock, patch
 
 from . import fixtures as eg
 from ...tests.db_helpers import (
@@ -69,7 +67,7 @@
         wim = eg.wim(0)
         account = eg.wim_account(0, 0)
         account['wim'] = wim
-        self.thread = WimThread(self.persist, account)
+        self.thread = WimThread(self.persist, {}, account)
         self.thread.connector = MagicMock()
 
     def assertTasksEqual(self, left, right):
@@ -284,7 +282,7 @@
         account = eg.wim_account(0, 0)
         account['wim'] = wim
         self.persist = MagicMock()
-        self.thread = WimThread(self.persist, account)
+        self.thread = WimThread(self.persist, {}, account)
         self.thread.connector = MagicMock()
 
         super(TestWimThread, self).setUp()
diff --git a/osm_ro/wim/tox.ini b/RO/osm_ro/wim/tox.ini
similarity index 63%
rename from osm_ro/wim/tox.ini
rename to RO/osm_ro/wim/tox.ini
index 29f1a8f..a426d4d 100644
--- a/osm_ro/wim/tox.ini
+++ b/RO/osm_ro/wim/tox.ini
@@ -1,3 +1,17 @@
+##
+# 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.
+##
+
 # This tox file allows the devs to run unit tests only for this subpackage.
 # In order to do so, cd into the directory and run `tox`
 
diff --git a/osm_ro/wim/wan_link_actions.py b/RO/osm_ro/wim/wan_link_actions.py
similarity index 92%
rename from osm_ro/wim/wan_link_actions.py
rename to RO/osm_ro/wim/wan_link_actions.py
index 034e415..458f3d5 100644
--- a/osm_ro/wim/wan_link_actions.py
+++ b/RO/osm_ro/wim/wan_link_actions.py
@@ -34,11 +34,9 @@
 # pylint: disable=E1101,E0203,W0201
 import json
 from pprint import pformat
-from sys import exc_info
+# from sys import exc_info
 from time import time
 
-from six import reraise
-
 from ..utils import filter_dict_keys as filter_keys
 from ..utils import merge_dicts, remove_none_items, safe_get, truncate
 from .actions import CreateAction, DeleteAction, FindAction
@@ -47,7 +45,7 @@
     NoRecordFound,
     NoExternalPortFound
 )
-from wimconn import WimConnectorError
+from .sdnconn import SdnConnectorError
 
 INSTANCE_NET_STATUS_ERROR = ('DOWN', 'ERROR', 'VIM_ERROR',
                              'DELETED', 'SCHEDULED_DELETION')
@@ -66,26 +64,26 @@
                 Infrastructure Manager system
             persistence: abstraction layer for the database
         """
-        fields = ('wim_status', 'wim_info', 'error_msg')
+        fields = ('sdn_status', 'sdn_info', 'error_msg')
         result = dict.fromkeys(fields)
 
         try:
             result.update(
                 connector
                 .get_connectivity_service_status(self.wim_internal_id))
-        except WimConnectorError as ex:
+        except SdnConnectorError as ex:
             self.logger.exception(ex)
-            result.update(wim_status='WIM_ERROR', error_msg=truncate(ex))
+            result.update(sdn_status='WIM_ERROR', error_msg=truncate(ex))
 
         result = filter_keys(result, fields)
 
         action_changes = remove_none_items({
             'extra': merge_dicts(self.extra, result),
-            'status': 'BUILD' if result['wim_status'] == 'BUILD' else None,
+            'status': 'BUILD' if result['sdn_status'] == 'BUILD' else None,
             'error_msg': result['error_msg'],
             'modified_at': time()})
-        link_changes = merge_dicts(result, status=result.pop('wim_status'))
-        # ^  Rename field: wim_status => status
+        link_changes = merge_dicts(result, status=result.pop('sdn_status'))
+        # ^  Rename field: sdn_status => status
 
         persistence.update_wan_link(self.item_id,
                                     remove_none_items(link_changes))
@@ -161,10 +159,10 @@
         Returns:
             dict: Record representing the wan_port_mapping associated to the
                   given instance_net. The expected fields are:
-                  **wim_id**, **datacenter_id**, **pop_switch_dpid** (the local
-                  network is expected to be connected at this switch),
-                  **pop_switch_port**, **wan_service_endpoint_id**,
-                  **wan_service_mapping_info**.
+                  **wim_id**, **datacenter_id**, **device_id** (the local
+                  network is expected to be connected at this switch dpid),
+                  **device_interface_id**, **service_endpoint_id**,
+                  **service_mapping_info**.
         """
         # First, we need to find a route from the datacenter to the outside
         # world. For that, we can use the rules given in the datacenter
@@ -187,26 +185,26 @@
 
             criteria = {
                 'wim_id': wim_account['wim_id'],
-                'pop_switch_dpid': external_port[0],
-                'pop_switch_port': external_port[1],
+                'device_id': external_port[0],
+                'device_interface_id': external_port[1],
                 'datacenter_id': datacenter_id}
 
             wan_port_mapping = persistence.query_one(
                 FROM='wim_port_mappings',
                 WHERE=criteria)
-        except NoRecordFound:
+        except NoRecordFound as e:
             ex = InconsistentState('No WIM port mapping found:'
                                    'wim_account: {}\ncriteria:\n{}'.format(
                                        self.wim_account_id, pformat(criteria)))
-            reraise(ex.__class__, ex, exc_info()[2])
+            raise ex from e
 
         # It is important to return encapsulation information if present
         mapping = merge_dicts(
-            wan_port_mapping.get('wan_service_mapping_info'),
+            wan_port_mapping.get('service_mapping_info'),
             filter_keys(vim_info, ('encapsulation_type', 'encapsulation_id'))
         )
 
-        return merge_dicts(wan_port_mapping, wan_service_mapping_info=mapping)
+        return merge_dicts(wan_port_mapping, service_mapping_info=mapping)
 
     def _get_port_sdn(self, ovim, instance_net):
         criteria = {'net_id': instance_net['sdn_net_id']}
@@ -312,9 +310,9 @@
 
     @staticmethod
     def _derive_connection_point(wan_info):
-        point = {'service_endpoint_id': wan_info['wan_service_endpoint_id']}
+        point = {'service_endpoint_id': wan_info['service_endpoint_id']}
         # TODO: Cover other scenarios, e.g. VXLAN.
-        details = wan_info.get('wan_service_mapping_info', {})
+        details = wan_info.get('service_mapping_info', {})
         if details.get('encapsulation_type') == 'vlan':
             point['service_endpoint_encapsulation_type'] = 'dot1q'
             point['service_endpoint_encapsulation_info'] = {
@@ -337,7 +335,7 @@
         """Store plugin/connector specific information in the database"""
         persistence.update_wan_link(self.item_id, {
             'wim_internal_id': service_uuid,
-            'wim_info': {'conn_info': conn_info},
+            'sdn_info': {'conn_info': conn_info},
             'status': 'BUILD'})
 
     def execute(self, connector, persistence, ovim, instance_nets):
@@ -355,7 +353,7 @@
                 connection_points
                 # TODO: other properties, e.g. bandwidth
             )
-        except (WimConnectorError, InconsistentState,
+        except (SdnConnectorError, InconsistentState,
                 NoExternalPortFound) as ex:
             self.logger.exception(ex)
             return self.fail(
@@ -414,12 +412,12 @@
 
         try:
             id = self.wim_internal_id
-            conn_info = safe_get(wan_link, 'wim_info.conn_info')
+            conn_info = safe_get(wan_link, 'sdn_info.conn_info')
             self.logger.debug('Connection Service %s (wan_link: %s):\n%s\n',
                               id, wan_link['uuid'],
                               json.dumps(conn_info, indent=4))
             result = connector.delete_connectivity_service(id, conn_info)
-        except (WimConnectorError, InconsistentState) as ex:
+        except (SdnConnectorError, InconsistentState) as ex:
             self.logger.exception(ex)
             return self.fail(
                 persistence,
diff --git a/osm_ro/wim/wim_thread.py b/RO/osm_ro/wim/wim_thread.py
similarity index 94%
rename from osm_ro/wim/wim_thread.py
rename to RO/osm_ro/wim/wim_thread.py
index f37aba7..3466193 100644
--- a/osm_ro/wim/wim_thread.py
+++ b/RO/osm_ro/wim/wim_thread.py
@@ -45,11 +45,10 @@
 from functools import partial
 from itertools import islice, chain, takewhile
 from operator import itemgetter, attrgetter
-from sys import exc_info
+# from sys import exc_info
 from time import time, sleep
 
-from six import reraise
-from six.moves import queue
+import queue
 
 from . import wan_link_actions
 from ..utils import ensure, partition, pipe
@@ -61,10 +60,8 @@
     UndefinedAction,
 )
 from .failing_connector import FailingConnector
-from .wimconn import WimConnectorError
-from .wimconn_dynpac import DynpacConnector
+from .sdnconn import SdnConnectorError
 from .wimconn_fake import FakeConnector
-from .wimconn_ietfl2vpn import WimconnectorIETFL2VPN
 
 ACTIONS = {
     'instance_wim_nets': wan_link_actions.ACTIONS
@@ -72,10 +69,8 @@
 
 CONNECTORS = {
     # "odl": wimconn_odl.OdlConnector,
-    "dynpac": DynpacConnector,
     "fake": FakeConnector,
-    "tapi": WimconnectorIETFL2VPN,
-    # Add extra connectors here
+    # Add extra connectors here not managed via plugins
 }
 
 
@@ -102,17 +97,21 @@
     MAX_RECOVERY_TIME = 180
     WAITING_TIME = 1      # Wait 1s for taks to arrive, when there are none
 
-    def __init__(self, persistence, wim_account, logger=None, ovim=None):
+    def __init__(self, persistence, plugins, wim_account, logger=None, ovim=None):
         """Init a thread.
 
         Arguments:
             persistence: Database abstraction layer
+            plugins: dictionary with the vim/sdn plugins
             wim_account: Record containing wim_account, tenant and wim
                 information.
         """
         name = '{}.{}.{}'.format(wim_account['wim']['name'],
                                  wim_account['name'], wim_account['uuid'])
         super(WimThread, self).__init__(name=name)
+        self.plugins = plugins
+        if "rosdn_fake" not in self.plugins:
+            self.plugins["rosdn_fake"] = FakeConnector
 
         self.name = name
         self.connector = None
@@ -161,9 +160,11 @@
             mapping = self.persist.query('wim_port_mappings',
                                          WHERE={'wim_id': wim['uuid']},
                                          error_if_none=False)
-            return CONNECTORS[wim['type']](wim, account, {
-                'service_endpoint_mapping': mapping or []
-            })
+            if wim["type"] in CONNECTORS:
+                return CONNECTORS[wim['type']](wim, account, {'service_endpoint_mapping': mapping or []})
+            else:    # load a plugin
+                return self.plugins["rosdn_" + wim["type"]](
+                    wim, account, {'service_endpoint_mapping': mapping or []})
         except DbBaseException as ex:
             error_msg = ('Error when retrieving WIM account ({})\n'
                          .format(account_id)) + str(ex)
@@ -171,8 +172,8 @@
         except KeyError as ex:
             error_msg = ('Unable to find the WIM connector for WIM ({})\n'
                          .format(wim['type'])) + str(ex)
-            self.logger.error(error_msg, exc_info=True)
-        except (WimConnectorError, Exception) as ex:
+            self.logger.error(error_msg)
+        except (SdnConnectorError, Exception) as ex:
             # TODO: Remove the Exception class here when the connector class is
             # ready
             error_msg = ('Error when loading WIM connector for WIM ({})\n'
@@ -343,9 +344,9 @@
         try:
             self.task_queue.put(task, False)
             return None
-        except queue.Full:
+        except queue.Full as e:
             ex = QueueFull(self.name)
-            reraise(ex.__class__, ex, exc_info()[2])
+            raise ex from e
 
     def reload(self):
         """Send a message to the running thread to reload itself"""
@@ -437,6 +438,6 @@
     try:
         factory = mapping[record['item']][record['action']]
         return factory(record, logger=logger)
-    except KeyError:
+    except KeyError as e:
         ex = UndefinedAction(record['item'], record['action'])
-        reraise(ex.__class__, ex, exc_info()[2])
+        raise ex from e
diff --git a/osm_ro/wim/wimconn_fake.py b/RO/osm_ro/wim/wimconn_fake.py
similarity index 80%
rename from osm_ro/wim/wimconn_fake.py
rename to RO/osm_ro/wim/wimconn_fake.py
index 36929f4..168996d 100644
--- a/osm_ro/wim/wimconn_fake.py
+++ b/RO/osm_ro/wim/wimconn_fake.py
@@ -22,12 +22,12 @@
 
 import logging
 from uuid import uuid4
-from .wimconn import WimConnector
-
+from .sdnconn import SdnConnectorBase, SdnConnectorError
+from http import HTTPStatus
 __author__ = "Alfonso Tierno <alfonso.tiernosepulveda@telefonica.com>"
 
 
-class FakeConnector(WimConnector):
+class FakeConnector(SdnConnectorBase):
     """Abstract base class for all the WIM connectors
 
     Arguments:
@@ -44,8 +44,8 @@
     An extra property, ``service_endpoint_mapping`` is created from ``config``.
     """
     def __init__(self, wim, wim_account, config=None, logger=None):
-        self.logger = logging.getLogger('openmano.wimconn.fake')
-        super(FakeConnector, self).__init__(wim, wim_account, config, logger)
+        self.logger = logger or logging.getLogger('openmano.sdnconn.fake')
+        super(FakeConnector, self).__init__(wim, wim_account, config, self.logger)
         self.logger.debug("__init: wim='{}' wim_account='{}'".format(wim, wim_account))
         self.connections = {}
         self.counter = 0
@@ -54,7 +54,7 @@
         """Check if the connector itself can access the WIM.
 
         Raises:
-            WimConnectorError: Issues regarding authorization, access to
+            SdnConnectorError: Issues regarding authorization, access to
                 external URLs, etc are detected.
         """
         self.logger.debug("check_credentials")
@@ -71,15 +71,15 @@
 
         Returns:
             dict: JSON/YAML-serializable dict that contains a mandatory key
-                ``wim_status`` associated with one of the following values::
+                ``sdn_status`` associated with one of the following values::
 
-                Additionally ``error_msg``(**str**) and ``wim_info``(**dict**)
+                Additionally ``error_msg``(**str**) and ``sdn_info``(**dict**)
                 keys can be used to provide additional status explanation or
                 new information available for the connectivity service.
         """
         self.logger.debug("get_connectivity_service_status: service_uuid='{}' conn_info='{}'".format(service_uuid,
                                                                                                      conn_info))
-        return {'wim_status': 'ACTIVE', 'wim_info': self.connectivity.get(service_uuid)}
+        return {'sdn_status': 'ACTIVE', 'sdn_info': self.connectivity.get(service_uuid)}
 
     def create_connectivity_service(self, service_type, connection_points,
                                     **kwargs):
@@ -90,9 +90,9 @@
         self.logger.debug("create_connectivity_service: service_type='{}' connection_points='{}', kwargs='{}'".
                           format(service_type, connection_points, kwargs))
         _id = str(uuid4())
-        self.connectivity[_id] = {"nb": self.counter}
+        self.connections[_id] = connection_points.copy()
         self.counter += 1
-        return _id, self.connectivity[_id]
+        return _id, None
 
     def delete_connectivity_service(self, service_uuid, conn_info=None):
         """Disconnect multi-site endpoints previously connected
@@ -100,7 +100,10 @@
         """
         self.logger.debug("delete_connectivity_service: service_uuid='{}' conn_info='{}'".format(service_uuid,
                                                                                                  conn_info))
-        self.connectivity.pop(service_uuid, None)
+        if service_uuid not in self.connections:
+            raise SdnConnectorError("connectivity {} not found".format(service_uuid),
+                                    http_code=HTTPStatus.NOT_FOUND.value)
+        self.connections.pop(service_uuid, None)
         return None
 
     def edit_connectivity_service(self, service_uuid, conn_info=None,
@@ -112,6 +115,10 @@
         """
         self.logger.debug("edit_connectivity_service: service_uuid='{}' conn_info='{}', connection_points='{}'"
                           "kwargs='{}'".format(service_uuid, conn_info, connection_points, kwargs))
+        if service_uuid not in self.connections:
+            raise SdnConnectorError("connectivity {} not found".format(service_uuid),
+                                    http_code=HTTPStatus.NOT_FOUND.value)
+        self.connections[service_uuid] = connection_points.copy()
         return None
 
     def clear_all_connectivity_services(self):
@@ -123,7 +130,7 @@
 
         """
         self.logger.debug("clear_all_connectivity_services")
-        self.connectivity.clear()
+        self.connections.clear()
         return None
 
     def get_all_active_connectivity_services(self):
@@ -131,7 +138,7 @@
         WIM.
 
         Raises:
-            WimConnectorException: In case of error.
+            SdnConnectorException: In case of error.
         """
         self.logger.debug("get_all_active_connectivity_services")
-        return self.connectivity
+        return self.connections
diff --git a/osm_ro/wim/wimconn_odl.py b/RO/osm_ro/wim/wimconn_odl.py
similarity index 95%
rename from osm_ro/wim/wimconn_odl.py
rename to RO/osm_ro/wim/wimconn_odl.py
index 2371046..e4af3c6 100644
--- a/osm_ro/wim/wimconn_odl.py
+++ b/RO/osm_ro/wim/wimconn_odl.py
@@ -31,12 +31,12 @@
 # funded by the European Commission under Grant number 761727 through the
 # Horizon 2020 and 5G-PPP programmes.
 ##
-from .wimconn import WimConnector
+from .sdnconn import SdnConnectorBase
 
 
 # TODO: Basically create this file
 
-class OdlConnector(WimConnector):
+class OdlConnector(SdnConnectorBase):
     def get_connectivity_service_status(self, link_uuid):
         raise NotImplementedError
 
diff --git a/RO/requirements.txt b/RO/requirements.txt
new file mode 100644
index 0000000..973b82d
--- /dev/null
+++ b/RO/requirements.txt
@@ -0,0 +1,23 @@
+##
+# 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.
+##
+
+PyYAML
+bottle
+MySQL-python
+jsonschema
+paramiko
+requests==2.18.*
+netaddr
+logutils
+git+https://osm.etsi.org/gerrit/osm/IM.git#egg=osm-im
diff --git a/RO/setup.py b/RO/setup.py
new file mode 100755
index 0000000..5cb1fe9
--- /dev/null
+++ b/RO/setup.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python3
+
+# 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.
+
+# from distutils.core import setup
+# from distutils.command.install_data import install_data
+from setuptools import setup
+from os import system
+# import glob
+
+_name = 'osm_ro'
+_description = 'OSM Resource Orchestrator'
+_author = 'ETSI OSM'
+_author_email = 'alfonso.tiernosepulveda@telefonica.com'
+_maintainer = 'garciadeblas'
+_maintainer_email = 'gerardo.garciadeblas@telefonica.com'
+_license = 'Apache 2.0'
+_url = 'https://osm.etsi.org/gitweb/?p=osm/RO.git;a=summary'
+_requirements = [
+    # TODO py3 revise
+    "osm-im",
+    "PyYAML",
+    "bottle",
+    "logutils",
+    "jsonschema",
+    "paramiko",
+    "mysqlclient",
+    #"MySQLdb",
+
+    # common to  VIMS
+    "requests",
+    "netaddr",  # openstack, aws, vmware
+]
+
+setup(
+    name=_name,
+    version_command=('git -C .. describe --match v* --tags --long --dirty', 'pep440-git-full'),
+    description = _description,
+    long_description = open('README.rst').read(),
+    author = _author,
+    author_email = _author_email,
+    maintainer = _maintainer,
+    maintainer_email = _maintainer_email,
+    url = _url,
+    license = _license,
+    packages = [_name],
+    #packages = ['osm_ro', 'osm_roclient'],
+    package_dir = {_name: _name},
+    # package_data = {_name: ['vnfs/*.yaml', 'vnfs/examples/*.yaml',
+    #                    'scenarios/*.yaml', 'scenarios/examples/*.yaml',
+    #                    'instance-scenarios/examples/*.yaml', 'database_utils/*',
+    #                    'scripts/*']},
+    # data_files = [('/etc/osm/', ['osm_ro/openmanod.cfg']),
+    #              ('/etc/systemd/system/', ['osm_ro/osm-ro.service']),
+    #              ],
+    scripts=['osm_ro/scripts/RO-start.sh'
+      #'openmanod', 'openmano', 'osm_ro/scripts/service-openmano', 'osm_ro/scripts/openmano-report',
+      ],
+    dependency_links=["git+https://osm.etsi.org/gerrit/osm/IM.git#egg=osm-im"],
+    install_requires=_requirements,
+    include_package_data=True,
+    setup_requires=['setuptools-version-command'],
+    #test_suite='nose.collector',
+)
+
diff --git a/RO/stdeb.cfg b/RO/stdeb.cfg
new file mode 100644
index 0000000..6260296
--- /dev/null
+++ b/RO/stdeb.cfg
@@ -0,0 +1,23 @@
+# 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.
+
+[DEFAULT]
+X-Python3-Version : >= 3.5
+Maintainer: Gerardo Garcia <gerardo.garciadeblas@telefonica.com>
+Depends3 : python3-bottle, python3-jsonschema, python3-mysqldb, python3-paramiko, python3-yaml,
+           libmysqlclient-dev, mysql-client,
+           python3-requests, python3-netaddr,
+           python3-osm-im,
+
+# TODO py3   libssl-dev, libffi-dev, python-logutils, python-lib-osm-openvim,
+# TODO py3   python3-networkx
diff --git a/test/RO_tests/afiinity_vnf/scenario_simple_2_vnf_afinnity.yaml b/RO/test/RO_tests/afiinity_vnf/scenario_simple_2_vnf_afinnity.yaml
similarity index 100%
rename from test/RO_tests/afiinity_vnf/scenario_simple_2_vnf_afinnity.yaml
rename to RO/test/RO_tests/afiinity_vnf/scenario_simple_2_vnf_afinnity.yaml
diff --git a/test/RO_tests/afiinity_vnf/vnfd_linux_2_vnfc_affinity.yaml b/RO/test/RO_tests/afiinity_vnf/vnfd_linux_2_vnfc_affinity.yaml
similarity index 100%
rename from test/RO_tests/afiinity_vnf/vnfd_linux_2_vnfc_affinity.yaml
rename to RO/test/RO_tests/afiinity_vnf/vnfd_linux_2_vnfc_affinity.yaml
diff --git a/test/RO_tests/empy_volume/scenario_additional_disk_empty_volume.yaml b/RO/test/RO_tests/empy_volume/scenario_additional_disk_empty_volume.yaml
similarity index 100%
rename from test/RO_tests/empy_volume/scenario_additional_disk_empty_volume.yaml
rename to RO/test/RO_tests/empy_volume/scenario_additional_disk_empty_volume.yaml
diff --git a/test/RO_tests/empy_volume/vnfd_additional_disk_empty_volume.yaml b/RO/test/RO_tests/empy_volume/vnfd_additional_disk_empty_volume.yaml
similarity index 100%
rename from test/RO_tests/empy_volume/vnfd_additional_disk_empty_volume.yaml
rename to RO/test/RO_tests/empy_volume/vnfd_additional_disk_empty_volume.yaml
diff --git a/test/RO_tests/floating_ip/scenario_floating_ip.yaml b/RO/test/RO_tests/floating_ip/scenario_floating_ip.yaml
similarity index 100%
rename from test/RO_tests/floating_ip/scenario_floating_ip.yaml
rename to RO/test/RO_tests/floating_ip/scenario_floating_ip.yaml
diff --git a/test/RO_tests/floating_ip/vnfd_floating_ip.yaml b/RO/test/RO_tests/floating_ip/vnfd_floating_ip.yaml
similarity index 100%
rename from test/RO_tests/floating_ip/vnfd_floating_ip.yaml
rename to RO/test/RO_tests/floating_ip/vnfd_floating_ip.yaml
diff --git a/test/RO_tests/image_based_volume/scenario_additional_disk_based_image.yaml b/RO/test/RO_tests/image_based_volume/scenario_additional_disk_based_image.yaml
similarity index 100%
rename from test/RO_tests/image_based_volume/scenario_additional_disk_based_image.yaml
rename to RO/test/RO_tests/image_based_volume/scenario_additional_disk_based_image.yaml
diff --git a/test/RO_tests/image_based_volume/vnfd_additional_disk_based_image.yaml b/RO/test/RO_tests/image_based_volume/vnfd_additional_disk_based_image.yaml
similarity index 100%
rename from test/RO_tests/image_based_volume/vnfd_additional_disk_based_image.yaml
rename to RO/test/RO_tests/image_based_volume/vnfd_additional_disk_based_image.yaml
diff --git a/test/RO_tests/no_port_security/scenario_vnf_no_port_security.yaml b/RO/test/RO_tests/no_port_security/scenario_vnf_no_port_security.yaml
similarity index 100%
rename from test/RO_tests/no_port_security/scenario_vnf_no_port_security.yaml
rename to RO/test/RO_tests/no_port_security/scenario_vnf_no_port_security.yaml
diff --git a/test/RO_tests/no_port_security/vnfd_no_port_security.yaml b/RO/test/RO_tests/no_port_security/vnfd_no_port_security.yaml
similarity index 100%
rename from test/RO_tests/no_port_security/vnfd_no_port_security.yaml
rename to RO/test/RO_tests/no_port_security/vnfd_no_port_security.yaml
diff --git a/test/RO_tests/passthrough/scenario_p2p_passthrough.yaml b/RO/test/RO_tests/passthrough/scenario_p2p_passthrough.yaml
similarity index 100%
rename from test/RO_tests/passthrough/scenario_p2p_passthrough.yaml
rename to RO/test/RO_tests/passthrough/scenario_p2p_passthrough.yaml
diff --git a/test/RO_tests/passthrough/vnfd_1passthrough.yaml b/RO/test/RO_tests/passthrough/vnfd_1passthrough.yaml
similarity index 100%
rename from test/RO_tests/passthrough/vnfd_1passthrough.yaml
rename to RO/test/RO_tests/passthrough/vnfd_1passthrough.yaml
diff --git a/test/RO_tests/pmp_passthrough/scenario_pmp_passthrough.yaml b/RO/test/RO_tests/pmp_passthrough/scenario_pmp_passthrough.yaml
similarity index 100%
rename from test/RO_tests/pmp_passthrough/scenario_pmp_passthrough.yaml
rename to RO/test/RO_tests/pmp_passthrough/scenario_pmp_passthrough.yaml
diff --git a/test/RO_tests/pmp_passthrough/vnfd_1passthrough.yaml b/RO/test/RO_tests/pmp_passthrough/vnfd_1passthrough.yaml
similarity index 100%
rename from test/RO_tests/pmp_passthrough/vnfd_1passthrough.yaml
rename to RO/test/RO_tests/pmp_passthrough/vnfd_1passthrough.yaml
diff --git a/test/RO_tests/pmp_sriov/scenario_pmp_sriov.yaml b/RO/test/RO_tests/pmp_sriov/scenario_pmp_sriov.yaml
similarity index 100%
rename from test/RO_tests/pmp_sriov/scenario_pmp_sriov.yaml
rename to RO/test/RO_tests/pmp_sriov/scenario_pmp_sriov.yaml
diff --git a/test/RO_tests/pmp_sriov/vnfd_1sriov.yaml b/RO/test/RO_tests/pmp_sriov/vnfd_1sriov.yaml
similarity index 100%
rename from test/RO_tests/pmp_sriov/vnfd_1sriov.yaml
rename to RO/test/RO_tests/pmp_sriov/vnfd_1sriov.yaml
diff --git a/test/RO_tests/pmp_sriov_passthrough/scenario_pmp_sriov_passthrough.yaml b/RO/test/RO_tests/pmp_sriov_passthrough/scenario_pmp_sriov_passthrough.yaml
similarity index 100%
rename from test/RO_tests/pmp_sriov_passthrough/scenario_pmp_sriov_passthrough.yaml
rename to RO/test/RO_tests/pmp_sriov_passthrough/scenario_pmp_sriov_passthrough.yaml
diff --git a/test/RO_tests/pmp_sriov_passthrough/vnfd_1passthrough.yaml b/RO/test/RO_tests/pmp_sriov_passthrough/vnfd_1passthrough.yaml
similarity index 100%
rename from test/RO_tests/pmp_sriov_passthrough/vnfd_1passthrough.yaml
rename to RO/test/RO_tests/pmp_sriov_passthrough/vnfd_1passthrough.yaml
diff --git a/test/RO_tests/pmp_sriov_passthrough/vnfd_1sriov.yaml b/RO/test/RO_tests/pmp_sriov_passthrough/vnfd_1sriov.yaml
similarity index 100%
rename from test/RO_tests/pmp_sriov_passthrough/vnfd_1sriov.yaml
rename to RO/test/RO_tests/pmp_sriov_passthrough/vnfd_1sriov.yaml
diff --git a/test/RO_tests/simple_2_vnf/scenario_simple_2_vnf.yaml b/RO/test/RO_tests/simple_2_vnf/scenario_simple_2_vnf.yaml
similarity index 100%
rename from test/RO_tests/simple_2_vnf/scenario_simple_2_vnf.yaml
rename to RO/test/RO_tests/simple_2_vnf/scenario_simple_2_vnf.yaml
diff --git a/test/RO_tests/simple_2_vnf/vnfd_linux.yaml b/RO/test/RO_tests/simple_2_vnf/vnfd_linux.yaml
similarity index 100%
rename from test/RO_tests/simple_2_vnf/vnfd_linux.yaml
rename to RO/test/RO_tests/simple_2_vnf/vnfd_linux.yaml
diff --git a/test/RO_tests/simple_cloud_init/scenario_simple-cloud-init.yaml b/RO/test/RO_tests/simple_cloud_init/scenario_simple-cloud-init.yaml
similarity index 100%
rename from test/RO_tests/simple_cloud_init/scenario_simple-cloud-init.yaml
rename to RO/test/RO_tests/simple_cloud_init/scenario_simple-cloud-init.yaml
diff --git a/test/RO_tests/simple_cloud_init/vnfd_linux-cloud-init.yaml b/RO/test/RO_tests/simple_cloud_init/vnfd_linux-cloud-init.yaml
similarity index 100%
rename from test/RO_tests/simple_cloud_init/vnfd_linux-cloud-init.yaml
rename to RO/test/RO_tests/simple_cloud_init/vnfd_linux-cloud-init.yaml
diff --git a/test/RO_tests/simple_count3/scenario_linux_count3.yaml b/RO/test/RO_tests/simple_count3/scenario_linux_count3.yaml
similarity index 100%
rename from test/RO_tests/simple_count3/scenario_linux_count3.yaml
rename to RO/test/RO_tests/simple_count3/scenario_linux_count3.yaml
diff --git a/test/RO_tests/simple_count3/vnfd_count3.yaml b/RO/test/RO_tests/simple_count3/vnfd_count3.yaml
similarity index 100%
rename from test/RO_tests/simple_count3/vnfd_count3.yaml
rename to RO/test/RO_tests/simple_count3/vnfd_count3.yaml
diff --git a/test/RO_tests/simple_linux/scenario_simple_linux.yaml b/RO/test/RO_tests/simple_linux/scenario_simple_linux.yaml
similarity index 100%
rename from test/RO_tests/simple_linux/scenario_simple_linux.yaml
rename to RO/test/RO_tests/simple_linux/scenario_simple_linux.yaml
diff --git a/test/RO_tests/simple_linux/vnfd_linux.yaml b/RO/test/RO_tests/simple_linux/vnfd_linux.yaml
similarity index 100%
rename from test/RO_tests/simple_linux/vnfd_linux.yaml
rename to RO/test/RO_tests/simple_linux/vnfd_linux.yaml
diff --git a/test/RO_tests/simple_multi_vnfc/scenario_multi_vnfc.yaml b/RO/test/RO_tests/simple_multi_vnfc/scenario_multi_vnfc.yaml
similarity index 100%
rename from test/RO_tests/simple_multi_vnfc/scenario_multi_vnfc.yaml
rename to RO/test/RO_tests/simple_multi_vnfc/scenario_multi_vnfc.yaml
diff --git a/test/RO_tests/simple_multi_vnfc/vnfd_linux_2VMs_v02.yaml b/RO/test/RO_tests/simple_multi_vnfc/vnfd_linux_2VMs_v02.yaml
similarity index 100%
rename from test/RO_tests/simple_multi_vnfc/vnfd_linux_2VMs_v02.yaml
rename to RO/test/RO_tests/simple_multi_vnfc/vnfd_linux_2VMs_v02.yaml
diff --git a/test/RO_tests/sr_iov/scenario_p2p_sriov.yaml b/RO/test/RO_tests/sr_iov/scenario_p2p_sriov.yaml
similarity index 100%
rename from test/RO_tests/sr_iov/scenario_p2p_sriov.yaml
rename to RO/test/RO_tests/sr_iov/scenario_p2p_sriov.yaml
diff --git a/test/RO_tests/sr_iov/vnfd_1sriov.yaml b/RO/test/RO_tests/sr_iov/vnfd_1sriov.yaml
similarity index 100%
rename from test/RO_tests/sr_iov/vnfd_1sriov.yaml
rename to RO/test/RO_tests/sr_iov/vnfd_1sriov.yaml
diff --git a/test/RO_tests/sriov_passthrough/scenario_p2p_sriov_passthrough.yaml b/RO/test/RO_tests/sriov_passthrough/scenario_p2p_sriov_passthrough.yaml
similarity index 100%
rename from test/RO_tests/sriov_passthrough/scenario_p2p_sriov_passthrough.yaml
rename to RO/test/RO_tests/sriov_passthrough/scenario_p2p_sriov_passthrough.yaml
diff --git a/test/RO_tests/sriov_passthrough/vnfd_1passthrough.yaml b/RO/test/RO_tests/sriov_passthrough/vnfd_1passthrough.yaml
similarity index 100%
rename from test/RO_tests/sriov_passthrough/vnfd_1passthrough.yaml
rename to RO/test/RO_tests/sriov_passthrough/vnfd_1passthrough.yaml
diff --git a/test/RO_tests/sriov_passthrough/vnfd_1sriov.yaml b/RO/test/RO_tests/sriov_passthrough/vnfd_1sriov.yaml
similarity index 100%
rename from test/RO_tests/sriov_passthrough/vnfd_1sriov.yaml
rename to RO/test/RO_tests/sriov_passthrough/vnfd_1sriov.yaml
diff --git a/test/RO_tests/v3_2vdu_set_ip_mac/scenario_2vdu_set_ip_mac.yaml b/RO/test/RO_tests/v3_2vdu_set_ip_mac/scenario_2vdu_set_ip_mac.yaml
similarity index 84%
rename from test/RO_tests/v3_2vdu_set_ip_mac/scenario_2vdu_set_ip_mac.yaml
rename to RO/test/RO_tests/v3_2vdu_set_ip_mac/scenario_2vdu_set_ip_mac.yaml
index fb76079..1b998b6 100644
--- a/test/RO_tests/v3_2vdu_set_ip_mac/scenario_2vdu_set_ip_mac.yaml
+++ b/RO/test/RO_tests/v3_2vdu_set_ip_mac/scenario_2vdu_set_ip_mac.yaml
@@ -1,3 +1,16 @@
+##
+# 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.
+##
 nsd:nsd-catalog:
     nsd:
     -   id:          test_2vdu_nsd
diff --git a/test/RO_tests/v3_2vdu_set_ip_mac/vnfd_2vdu_set_ip_mac.yaml b/RO/test/RO_tests/v3_2vdu_set_ip_mac/vnfd_2vdu_set_ip_mac.yaml
similarity index 84%
rename from test/RO_tests/v3_2vdu_set_ip_mac/vnfd_2vdu_set_ip_mac.yaml
rename to RO/test/RO_tests/v3_2vdu_set_ip_mac/vnfd_2vdu_set_ip_mac.yaml
index e790a9c..c95162e 100644
--- a/test/RO_tests/v3_2vdu_set_ip_mac/vnfd_2vdu_set_ip_mac.yaml
+++ b/RO/test/RO_tests/v3_2vdu_set_ip_mac/vnfd_2vdu_set_ip_mac.yaml
@@ -1,3 +1,16 @@
+##
+# 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.
+##
 vnfd-catalog:
     vnfd:
     -   connection-point:
diff --git a/test/RO_tests/v3_2vdu_set_ip_mac/vnfd_2vdu_set_ip_mac2.yaml b/RO/test/RO_tests/v3_2vdu_set_ip_mac/vnfd_2vdu_set_ip_mac2.yaml
similarity index 84%
rename from test/RO_tests/v3_2vdu_set_ip_mac/vnfd_2vdu_set_ip_mac2.yaml
rename to RO/test/RO_tests/v3_2vdu_set_ip_mac/vnfd_2vdu_set_ip_mac2.yaml
index 6c4b6cf..ad574a1 100644
--- a/test/RO_tests/v3_2vdu_set_ip_mac/vnfd_2vdu_set_ip_mac2.yaml
+++ b/RO/test/RO_tests/v3_2vdu_set_ip_mac/vnfd_2vdu_set_ip_mac2.yaml
@@ -1,3 +1,16 @@
+##
+# 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.
+##
 vnfd-catalog:
     vnfd:
     -   connection-point:
diff --git a/test/basictest.sh b/RO/test/basictest.sh
similarity index 100%
rename from test/basictest.sh
rename to RO/test/basictest.sh
diff --git a/test/test-multivim.sh b/RO/test/test-multivim.sh
similarity index 100%
rename from test/test-multivim.sh
rename to RO/test/test-multivim.sh
diff --git a/test/test_RO.py b/RO/test/test_RO.py
similarity index 99%
rename from test/test_RO.py
rename to RO/test/test_RO.py
index a777f69..030dfe0 100755
--- a/test/test_RO.py
+++ b/RO/test/test_RO.py
@@ -388,7 +388,7 @@
 
         for vnfd in vnfd_files:
             with open(vnfd, 'r') as stream:
-                vnf_descriptor = yaml.load(stream)
+                vnf_descriptor = yaml.load(stream, Loader=yaml.Loader)
 
             #internal_connections_list = vnf_descriptor['vnf']['internal-connections']
             internal_connections_list = vnf_descriptor['vnfd-catalog']['vnfd'][0]['ip-profiles']
@@ -765,7 +765,7 @@
 
         for vnfd in vnfd_files:
             with open(vnfd, 'r') as stream:
-                vnf_descriptor = yaml.load(stream)
+                vnf_descriptor = yaml.load(stream, Loader=yaml.Loader)
 
             vnfc_list = vnf_descriptor['vnf']['VNFC']
             for item in vnfc_list:
@@ -2100,7 +2100,7 @@
         scenario_descriptors = []
         for descriptor_file in descriptor_files:
             with open(descriptor_file, 'r') as stream:
-                descriptor = yaml.load(stream)
+                descriptor = yaml.load(stream, Loader=yaml.Loader)
                 if "vnf" in descriptor or "vnfd:vnfd-catalog" in descriptor or "vnfd-catalog" in descriptor:
                     vnf_descriptors.append(descriptor)
                 else:
@@ -2168,7 +2168,7 @@
         self.__class__.test_index += 1
 
         if test_config["manual"]:
-            raw_input('Scenario has been deployed. Perform manual check and press any key to resume')
+            input('Scenario has been deployed. Perform manual check and press any key to resume')
             return
 
         keep_waiting = test_config["timeout"]
@@ -2234,7 +2234,7 @@
 
         tenant_name = args.tenant_name
         test_config['tenant'] = tenant_name
-        config_params = yaml.load(args.config_param)
+        config_params = yaml.load(args.config_param, Loader=yaml.Loader)
         org_name = config_params.get('orgname')
         org_user = config_params.get('user')
         org_passwd = config_params.get('passwd')
@@ -2256,7 +2256,7 @@
 
         tenant_name = args.tenant_name
         test_config['tenant'] = tenant_name
-        config_params = yaml.load(args.config_param)
+        config_params = yaml.load(args.config_param, Loader=yaml.Loader)
         os_user = config_params.get('user')
         os_passwd = config_params.get('passwd')
         vim_url = args.endpoint_url
diff --git a/test/test_on_container.sh b/RO/test/test_on_container.sh
similarity index 100%
rename from test/test_on_container.sh
rename to RO/test/test_on_container.sh
diff --git a/test/test_openmanocli.sh b/RO/test/test_openmanocli.sh
similarity index 100%
rename from test/test_openmanocli.sh
rename to RO/test/test_openmanocli.sh
diff --git a/test/test_openmanoclient.py b/RO/test/test_openmanoclient.py
similarity index 100%
rename from test/test_openmanoclient.py
rename to RO/test/test_openmanoclient.py
diff --git a/test/test_osconnector.py b/RO/test/test_osconnector.py
similarity index 69%
rename from test/test_osconnector.py
rename to RO/test/test_osconnector.py
index 92d5437..3619ae4 100755
--- a/test/test_osconnector.py
+++ b/RO/test/test_osconnector.py
@@ -49,27 +49,27 @@
 version="0.1"
 
 def usage():
-    print "Usage: ", sys.argv[0], "[options]"
-    print "  -v|--version            openstack version (by default 2)"
-    print "  -u|--username USER      user to authenticate (by default bash:OS_USERNAME)"
-    print "  -p|--password PASSWD    password to authenticate (by default bash:OS_PASSWORD)"
-    print "  -U|--auth_url URL       url of authentication over keystone (by default bash:OS_AUTH_URL)"
-    print "  -t|--tenant_name TENANT password to authenticate (by default bash:OS_TENANT_NAME)"
-    print "  -i|--image IMAGE        use this local path or url for loading image (by default cirros)"
-    print "  --skip-admin-tests      skip tests that requires administrative permissions, like create tenants"
-    print "  -h|--help               shows this help"
+    print("Usage: ", sys.argv[0], "[options]")
+    print("  -v|--version            openstack version (by default 2)")
+    print("  -u|--username USER      user to authenticate (by default bash:OS_USERNAME)")
+    print("  -p|--password PASSWD    password to authenticate (by default bash:OS_PASSWORD)")
+    print("  -U|--auth_url URL       url of authentication over keystone (by default bash:OS_AUTH_URL)")
+    print("  -t|--tenant_name TENANT password to authenticate (by default bash:OS_TENANT_NAME)")
+    print("  -i|--image IMAGE        use this local path or url for loading image (by default cirros)")
+    print("  --skip-admin-tests      skip tests that requires administrative permissions, like create tenants")
+    print("  -h|--help               shows this help")
     return
 
 def delete_items():
     global myvim
     global rollback_list
-    print "Making rollback, deleting items"
+    print("Making rollback, deleting items")
     for i in range(len(rollback_list)-1, -1, -1):
         item,name,id_ = rollback_list[i]
         if item=="creds":
-            print ("changing credentials %s='%s'" % (name, id_)).ljust(50),
+            print("changing credentials {}='{}'".format(name, id_)).ljust(50),
         else:
-            print ("deleting %s '%s'" % (item, name)).ljust(50),
+            print("deleting {} '{}'".format(item, name)).ljust(50),
         sys.stdout.flush()
         if item=="flavor":
             result,message=myvim.delete_tenant_flavor(id_)
@@ -91,26 +91,26 @@
                 result=-1
                 message= "  " + str(type(e))[6:-1] + ": "+  str(e)
         else:
-            print "Internal error unknown item rollback %s,%s,%s" % (item,name,id_)
+            print("Internal error unknown item rollback {},{},{}".format(item,name,id_))
             continue
         if result<0:
-            print " Fail"
-            print "  VIM response:", message
+            print(" Fail")
+            print("  VIM response:", message)
             continue
         else:
-            print " Ok"
+            print(" Ok")
 
 if __name__=="__main__":
     global myvim
     global rollback_list
-    #print "(c) Copyright Telefonica"
+    #print("(c) Copyright Telefonica"
     rollback_list=[]
     try:
         opts, args = getopt.getopt(sys.argv[1:], "hv:u:U:p:t:i:",
                  ["username=", "help", "version=", "password=", "tenant=", "url=","skip-admin-tests",'image='])
     except getopt.GetoptError as err:
-        # print help information and exit:
-        print "Error:", err # will print something like "option -a not recognized"
+        # print(help information and exit:
+        print("Error:", err) # will print something like "option -a not recognized")
         usage()
         sys.exit(2)
         
@@ -144,129 +144,129 @@
             assert False, "Unhandled option"
  
     if creds['auth_url']==None:
-        print "you must provide openstack url with -U or bash OS_AUTH_URL"
+        print("you must provide openstack url with -U or bash OS_AUTH_URL")
         sys.exit()
-    print "creds:", creds
+    print("creds:", creds)
     
 
     try:
-        print 'load osconnector class'.ljust(50),
+        print('load osconnector class'.ljust(50))
         sys.stdout.flush()
         try:
             myvim=osconnector.osconnector(uuid=None, name='test-openstack', tenant=creds['tenant_name'], 
                 url=creds['auth_url'], url_admin=None,
                 user=creds['username'], passwd=creds['password'],
                 debug = False, config={'network_vlan_ranges':'physnet_sriov'} )
-            print " Ok"
+            print(" Ok")
         except Exception as e:
-            print " Fail"
-            print str(type(e))[6:-1] + ": "+  str(e) 
+            print(" Fail")
+            print(str(type(e))[6:-1] + ": "+  str(e))
             exit(-1)
         
         if not skip_admin_tests:
             tenant_name="tos-tenant"
-            print ("creating new tenant '%s'" % tenant_name).ljust(50),
+            print("creating new tenant '{}'".format(tenant_name)).ljust(50),
             sys.stdout.flush()
             result,new_tenant=myvim.new_tenant(tenant_name, "test tenant_description, trying a long description to get the limit. 2 trying a long description to get the limit. 3. trying a long description to get the limit.")
             if result<0:
-                print " Fail"
-                print "  you can skip tenant creation with param'--skip-admin-tests'"
-                print "  VIM response:", new_tenant
+                print(" Fail")
+                print("  you can skip tenant creation with param'--skip-admin-tests'")
+                print("  VIM response:", new_tenant)
                 exit(-1)
             else:
-                print " Ok", new_tenant
+                print(" Ok", new_tenant)
                 rollback_list.append(("tenant",tenant_name,new_tenant))
 
             user_name="tos-user"
-            print ("creating new user '%s'" % user_name).ljust(50),
+            print("creating new user '{}'".format(user_name).ljust(50), end="")
             sys.stdout.flush()
             result,new_user=myvim.new_user(user_name, user_name, tenant_id=new_tenant)
             if result<0:
-                print " Fail"
-                print "  VIM response:", new_user
+                print(" Fail")
+                print("  VIM response:", new_user)
                 exit(-1)
             else:
-                print " Ok", new_user
+                print(" Ok", new_user)
                 rollback_list.append(("user",user_name,new_user))
                     
         name="tos-fl1"
-        print ("creating new flavor '%s'"%name).ljust(50),
+        print("creating new flavor '{}'".format(name)).ljust(50),
         sys.stdout.flush()
         flavor={}
         flavor['name']=name
         result,new_flavor1=myvim.new_tenant_flavor(flavor, True)
         if result<0:
-            print " Fail"
-            print "  VIM response:", new_flavor1
+            print(" Fail")
+            print("  VIM response:", new_flavor1)
             exit(-1)
         else:
-            print " Ok", new_flavor1
+            print(" Ok", new_flavor1)
             rollback_list.append(("flavor",name,new_flavor1))
             
         name="tos-cirros"
-        print ("creating new image '%s'"%name).ljust(50),
+        print("creating new image '{}'".format(name).ljust(50))
         sys.stdout.flush()
         image={}
         image['name']=name
         image['location']=image_path #"/home/atierno/cirros-0.3.3-x86_64-disk.img"
         result,new_image1=myvim.new_tenant_image(image)
         if result<0:
-            print " Fail"
-            print "  VIM response:", new_image1
+            print(" Fail")
+            print("  VIM response:", new_image1)
             exit(-1)
         else:
-            print " Ok", new_image1
+            print(" Ok", new_image1)
             rollback_list.append(("image",name, new_image1))
 
         if not skip_admin_tests:
             try:
-                print 'changing credentials to new tenant'.ljust(50),
+                print('changing credentials to new tenant'.ljust(50))
                 sys.stdout.flush()
                 myvim['tenant']  =tenant_name
                 myvim['user']=user_name
                 myvim['passwd']=user_name
-                print " Ok"
+                print(" Ok")
                 rollback_list.append(("creds", "tenant", creds["tenant_name"]))
                 rollback_list.append(("creds", "user",   creds["username"]))
                 rollback_list.append(("creds", "passwd", creds["password"]))
             except Exception as e:
-                print " Fail"
-                print " Error setting osconnector to new tenant:", str(type(e))[6:-1] + ": "+  str(e)
+                print(" Fail")
+                print(" Error setting osconnector to new tenant:", str(type(e))[6:-1] + ": "+  str(e))
                 exit(-1)
 
         name="tos-net-bridge"
-        print ("creating new net '%s'"%name).ljust(50),
+        print("creating new net '{}'".format(name)).ljust(50),
         sys.stdout.flush()
         result,new_net1=myvim.new_tenant_network(name, "bridge")
         if result<0:
-            print " Fail"
-            print "  VIM response:", new_net1
+            print(" Fail")
+            print("  VIM response:", new_net1)
             exit(-1)
         else:
-            print " Ok", new_net1
+            print(" Ok", new_net1)
             rollback_list.append(("network",name, new_net1))
 
         name="tos-vm-cloud"
-        print ("creating new VM '%s'"%name).ljust(50),
+        print("creating new VM '{}'".format(name).ljust(50))
         sys.stdout.flush()
         result,new_vm1=myvim.new_tenant_vminstance(name, "vm-cloud-description", False,new_image1,new_flavor1,
                                     [{"net_id":new_net1, "type":"virtio"}] )
         if result<0:
-            print " Fail"
-            print "  VIM response:", new_vm1
+            print(" Fail")
+            print("  VIM response:", new_vm1)
             exit(-1)
         else:
-            print " Ok", new_vm1
+            print(" Ok", new_vm1)
             rollback_list.append(("vm",name, new_vm1))
 
             
-        print 'DONE  Ok'
-        print "Type ENTER to delete items"
-        raw_input('> ')  
+        print('DONE  Ok')
+        print("Type ENTER to delete items")
+        input('> ')
         exit()      
               
     except KeyboardInterrupt:
-        print " Canceled!"
+        print(" Canceled!")
     except SystemExit:
         pass
     if len(rollback_list):
diff --git a/test/test_vimconn.sh b/RO/test/test_vimconn.sh
similarity index 100%
rename from test/test_vimconn.sh
rename to RO/test/test_vimconn.sh
diff --git a/RO/tox.ini b/RO/tox.ini
new file mode 100644
index 0000000..810ab39
--- /dev/null
+++ b/RO/tox.ini
@@ -0,0 +1,35 @@
+# 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.
+
+[tox]
+#envlist = py27,py3
+envlist = py35
+toxworkdir={homedir}/.tox
+
+[testenv]
+deps=nose
+     mock
+commands=nosetests
+
+[testenv:flake8]
+basepython = python
+deps = flake8
+# TODO for the moment few files are tested.
+commands = flake8 osm_ro/wim  --max-line-length 120 \
+    --exclude .svn,CVS,.gz,.git,__pycache__,.tox,local,temp,osm_im --ignore W291,W293,E226,E402,W504
+
+[testenv:build]
+basepython = python3
+deps = stdeb
+       setuptools-version-command
+commands = python3 setup.py --command-packages=stdeb.command bdist_deb
diff --git a/database_utils/migrations/down/35_remove_sfc_ingress_and_egress.sql b/database_utils/migrations/down/35_remove_sfc_ingress_and_egress.sql
deleted file mode 100644
index 01f38f4..0000000
--- a/database_utils/migrations/down/35_remove_sfc_ingress_and_egress.sql
+++ /dev/null
@@ -1,16 +0,0 @@
---
--- Removing ingress and egress ports for SFC purposes.
--- Inserting only one port for ingress and egress.
---
-
-ALTER TABLE sce_rsp_hops
-  DROP FOREIGN KEY FK_interfaces_rsp_hop_ingress,
-  CHANGE COLUMN ingress_interface_id interface_id VARCHAR(36) NOT NULL
-    AFTER if_order,
-  ADD CONSTRAINT FK_interfaces_rsp_hop
-    FOREIGN KEY (interface_id)
-    REFERENCES interfaces (uuid) ON UPDATE CASCADE ON DELETE CASCADE,
-  DROP FOREIGN KEY FK_interfaces_rsp_hop_egress,
-  DROP COLUMN egress_interface_id;
-
-DELETE FROM schema_version WHERE version_int='35';
diff --git a/devops-stages/stage-archive.sh b/devops-stages/stage-archive.sh
index cc1cfc0..2bc3e4d 100755
--- a/devops-stages/stage-archive.sh
+++ b/devops-stages/stage-archive.sh
@@ -1,8 +1,22 @@
 #!/bin/sh
+
+# 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.
+
 rm -rf pool
 rm -rf dists
 mkdir -p pool/RO
-mv .build/*.deb pool/RO/
+mv deb_dist/*.deb pool/RO/
 mkdir -p dists/unstable/RO/binary-amd64/
 apt-ftparchive packages pool/RO > dists/unstable/RO/binary-amd64/Packages
 gzip -9fk dists/unstable/RO/binary-amd64/Packages
diff --git a/devops-stages/stage-build.sh b/devops-stages/stage-build.sh
index 25de71a..b48eaa3 100755
--- a/devops-stages/stage-build.sh
+++ b/devops-stages/stage-build.sh
@@ -1,4 +1,66 @@
-#!/bin/sh
-make clean all BRANCH=master
-#make install && \
-#make test
+#!/bin/bash
+
+# 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.
+
+rm -rf deb_dist/*
+mkdir -p deb_dist
+
+# main RO module
+make -C RO clean package BRANCH=master
+cp RO/deb_dist/python3-osm-ro_*.deb deb_dist/
+
+# RO client
+make -C RO-client clean package
+cp RO-client/deb_dist/python3-osm-roclient_*.deb deb_dist/
+
+# VIM vmware plugin
+make -C RO-VIM-vmware clean package
+cp RO-VIM-vmware/deb_dist/python3-osm-rovim-vmware_*.deb deb_dist/
+
+# VIM Openstack plugin
+make -C RO-VIM-openstack clean package
+cp RO-VIM-openstack/deb_dist/python3-osm-rovim-openstack_*.deb deb_dist/
+
+# VIM Openvim plugin
+make -C RO-VIM-openvim clean package
+cp RO-VIM-openvim/deb_dist/python3-osm-rovim-openvim_*.deb deb_dist/
+
+# VIM AWS plugin
+make -C RO-VIM-aws clean package
+cp RO-VIM-aws/deb_dist/python3-osm-rovim-aws_*.deb deb_dist/
+
+# VIM fos plugin
+make -C RO-VIM-fos clean package
+cp RO-VIM-fos/deb_dist/python3-osm-rovim-fos_*.deb deb_dist/
+
+# VIM azure plugin
+make -C RO-VIM-azure clean package
+cp RO-VIM-azure/deb_dist/python3-osm-rovim-azure_*.deb deb_dist/
+
+# VIM Opennebula plugin
+make -C RO-VIM-opennebula clean package
+cp RO-VIM-opennebula/deb_dist/python3-osm-rovim-opennebula_*.deb deb_dist/
+
+# SDN Dynpack plugin
+make -C RO-SDN-dynpac clean package
+cp RO-SDN-dynpac/deb_dist/python3-osm-rosdn-dynpac_*.deb deb_dist/
+
+# SDN Tapi plugin
+make -C RO-SDN-tapi clean package
+cp RO-SDN-tapi/deb_dist/python3-osm-rosdn-tapi_*.deb deb_dist/
+
+# SDN Onos openflow
+make -C RO-SDN-onos_openflow clean package
+cp RO-SDN-onos_openflow/deb_dist/python3-osm-rosdn-onosof_*.deb deb_dist/
+
diff --git a/devops-stages/stage-test.sh b/devops-stages/stage-test.sh
index cb72fb1..13cef85 100755
--- a/devops-stages/stage-test.sh
+++ b/devops-stages/stage-test.sh
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-flake8 osm_ro/wim osm_ro/vim_thread.py --max-line-length 120 \
+flake8 RO/osm_ro/wim RO/osm_ro/vim_thread.py --max-line-length 120 \
     --exclude .svn,CVS,.gz,.git,__pycache__,.tox,local,temp,osm_im --ignore W291,W293,E226,E402,W504
 
diff --git a/docker/Dockerfile-local b/docker/Dockerfile-local
deleted file mode 100644
index 1dff02d..0000000
--- a/docker/Dockerfile-local
+++ /dev/null
@@ -1,92 +0,0 @@
-##
-# Copyright {yyyy} {name of copyright owner}
-#
-# 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.
-##
-
-########################################################################
-
-from ubuntu:18.04
-
-LABEL authors="Gennadiy Dubina, Alfonso Tierno, Gerardo Garcia"
-
-RUN apt-get update && \
-    DEBIAN_FRONTEND=noninteractive apt-get -y install software-properties-common && \
-    DEBIAN_FRONTEND=noninteractive apt-get update && \
-    DEBIAN_FRONTEND=noninteractive apt-get -y install git python python-pip && \
-    DEBIAN_FRONTEND=noninteractive apt-get -y install wget tox && \
-    DEBIAN_FRONTEND=noninteractive pip2 install pip==9.0.3 && \
-    DEBIAN_FRONTEND=noninteractive pip2 install -U progressbar pyvmomi pyvcloud==19.1.1 && \
-    DEBIAN_FRONTEND=noninteractive pip2 install -U fog05rest && \
-    DEBIAN_FRONTEND=noninteractive pip2 install -U azure && \
-    DEBIAN_FRONTEND=noninteractive apt-get -y install python-requests && \
-    DEBIAN_FRONTEND=noninteractive apt-get -y install python-novaclient python-keystoneclient python-glanceclient python-cinderclient python-neutronclient python-networking-l2gw && \
-    DEBIAN_FRONTEND=noninteractive apt-get -y install python-cffi libmysqlclient-dev libssl-dev libffi-dev python-mysqldb && \
-    DEBIAN_FRONTEND=noninteractive apt-get -y install python-openstacksdk python-openstackclient && \
-    DEBIAN_FRONTEND=noninteractive apt-get -y install python-networkx && \
-    DEBIAN_FRONTEND=noninteractive apt-get -y install genisoimage && \
-    DEBIAN_FRONTEND=noninteractive pip2 install untangle && \
-    DEBIAN_FRONTEND=noninteractive pip2 install pyone && \
-    DEBIAN_FRONTEND=noninteractive pip2 install -e git+https://github.com/python-oca/python-oca#egg=oca && \
-    DEBIAN_FRONTEND=noninteractive apt-get -y install mysql-client
-
-COPY . /root/RO
-
-RUN /root/RO/scripts/install-osm-im.sh --develop && \
-    /root/RO/scripts/install-lib-osm-openvim.sh --develop && \
-    make -C /root/RO prepare && \
-    mkdir -p /var/log/osm && \
-    pip2 install -e /root/RO/build && \
-    rm -rf /root/.cache && \
-    apt-get clean && \
-    rm -rf /var/lib/apt/lists/*
-
-VOLUME /var/log/osm
-
-EXPOSE 9090
-
-# Two mysql databases are needed (DB and DB_OVIM). Can be hosted on same or separated containers
-# These ENV must be provided
-# RO_DB_HOST: host of the main
-# RO_DB_OVIM_HOST: ...        if empty RO_DB_HOST is assumed
-# RO_DB_ROOT_PASSWORD: this has to be provided first time for creating database. It will create and init only if empty!
-# RO_DB_OVIM_ROOT_PASSWORD: ...  if empty RO_DB_ROOT_PASSWORD is assumed
-# RO_DB_USER:    default value 'mano'
-# RO_DB_OVIM_USER:       default value 'mano'
-# RO_DB_PASSWORD:        default value 'manopw'
-# RO_DB_OVIM_PASSWORD:        default value 'manopw'
-# RO_DB_PORT:             default value '3306'
-# RO_DB_OVIM_PORT:        default value '3306'
-# RO_DB_NAME:             default value 'mano_db'
-# RO_DB_OVIM_NAME:        default value 'mano_vim_db'
-# RO_LOG_FILE:            default log to stderr if not defined
-
-ENV RO_DB_HOST="" \
-    RO_DB_OVIM_HOST="" \
-    RO_DB_ROOT_PASSWORD="" \
-    RO_DB_OVIM_ROOT_PASSWORD="" \
-    RO_DB_USER=mano \
-    RO_DB_OVIM_USER=mano \
-    RO_DB_PASSWORD=manopw \
-    RO_DB_OVIM_PASSWORD=manopw \
-    RO_DB_PORT=3306 \
-    RO_DB_OVIM_PORT=3306 \
-    RO_DB_NAME=mano_db \
-    RO_DB_OVIM_NAME=mano_vim_db \
-    OPENMANO_TENANT=osm \
-    RO_LOG_LEVEL=DEBUG
-
-CMD RO-start.sh
-
-# HEALTHCHECK --start-period=30s --interval=10s --timeout=5s --retries=12 \
-#  CMD curl --silent --fail localhost:9090/openmano/tenants || exit 1
diff --git a/osm_ro/__init__.py b/osm_ro/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/osm_ro/__init__.py
+++ /dev/null
diff --git a/osm_ro/http_tools/__init__.py b/osm_ro/http_tools/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/osm_ro/http_tools/__init__.py
+++ /dev/null
diff --git a/osm_ro/http_tools/tests/__init__.py b/osm_ro/http_tools/tests/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/osm_ro/http_tools/tests/__init__.py
+++ /dev/null
diff --git a/osm_ro/osm-ro.service b/osm_ro/osm-ro.service
deleted file mode 100644
index 2246885..0000000
--- a/osm_ro/osm-ro.service
+++ /dev/null
@@ -1,11 +0,0 @@
-[Unit]
-Description=openmano server (OSM RO)
-After=mysql.service
-
-[Service]
-ExecStart=/usr/bin/openmanod -c /etc/osm/openmanod.cfg --log-file=/var/log/osm/openmano.log
-Restart=always
-
-[Install]
-WantedBy=multi-user.target
-
diff --git a/osm_ro/tests/__init__.py b/osm_ro/tests/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/osm_ro/tests/__init__.py
+++ /dev/null
diff --git a/osm_ro/wim/__init__.py b/osm_ro/wim/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/osm_ro/wim/__init__.py
+++ /dev/null
diff --git a/osm_ro/wim/tests/__init__.py b/osm_ro/wim/tests/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/osm_ro/wim/tests/__init__.py
+++ /dev/null
diff --git a/osm_ro/wim/wimconn.py b/osm_ro/wim/wimconn.py
deleted file mode 100644
index 92b6db0..0000000
--- a/osm_ro/wim/wimconn.py
+++ /dev/null
@@ -1,236 +0,0 @@
-# -*- coding: utf-8 -*-
-##
-# Copyright 2018 University of Bristol - High Performance Networks Research
-# Group
-# All Rights Reserved.
-#
-# Contributors: Anderson Bravalheri, Dimitrios Gkounis, Abubakar Siddique
-# Muqaddas, Navdeep Uniyal, Reza Nejabati and Dimitra Simeonidou
-#
-# 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.
-#
-# For those usages not covered by the Apache License, Version 2.0 please
-# contact with: <highperformance-networks@bristol.ac.uk>
-#
-# Neither the name of the University of Bristol nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# This work has been performed in the context of DCMS UK 5G Testbeds
-# & Trials Programme and in the framework of the Metro-Haul project -
-# funded by the European Commission under Grant number 761727 through the
-# Horizon 2020 and 5G-PPP programmes.
-##
-"""The WIM connector is responsible for establishing wide area network
-connectivity.
-
-It receives information from the WimThread/WAN Actions about the endpoints of
-a link that spans across multiple datacenters and stablish a path between them.
-"""
-import logging
-
-from ..http_tools.errors import HttpMappedError
-
-
-class WimConnectorError(HttpMappedError):
-    """Base Exception for all connector related errors"""
-
-
-class WimConnector(object):
-    """Abstract base class for all the WIM connectors
-
-    Arguments:
-        wim (dict): WIM record, as stored in the database
-        wim_account (dict): WIM account record, as stored in the database
-        config (dict): optional persistent information related to an specific
-            connector.  Inside this dict, a special key,
-            ``service_endpoint_mapping`` provides the internal endpoint
-            mapping.
-        logger (logging.Logger): optional logger object. If none is passed
-            ``openmano.wim.wimconn`` is used.
-
-    The arguments of the constructor are converted to object attributes.
-    An extra property, ``service_endpoint_mapping`` is created from ``config``.
-    """
-    def __init__(self, wim, wim_account, config=None, logger=None):
-        self.logger = logger or logging.getLogger('openmano.wim.wimconn')
-
-        self.wim = wim
-        self.wim_account = wim_account
-        self.config = config or {}
-        self.service_endpoint_mapping = (
-            config.get('service_endpoint_mapping', []))
-
-    def check_credentials(self):
-        """Check if the connector itself can access the WIM.
-
-        Raises:
-            WimConnectorError: Issues regarding authorization, access to
-                external URLs, etc are detected.
-        """
-        raise NotImplementedError
-
-    def get_connectivity_service_status(self, service_uuid, conn_info=None):
-        """Monitor the status of the connectivity service established
-
-        Arguments:
-            service_uuid (str): UUID of the connectivity service
-            conn_info (dict or None): Information returned by the connector
-                during the service creation/edition and subsequently stored in
-                the database.
-
-        Returns:
-            dict: JSON/YAML-serializable dict that contains a mandatory key
-                ``wim_status`` associated with one of the following values::
-
-                    {'wim_status': 'ACTIVE'}
-                        # The service is up and running.
-
-                    {'wim_status': 'INACTIVE'}
-                        # The service was created, but the connector
-                        # cannot determine yet if connectivity exists
-                        # (ideally, the caller needs to wait and check again).
-
-                    {'wim_status': 'DOWN'}
-                        # Connection was previously established,
-                        # but an error/failure was detected.
-
-                    {'wim_status': 'ERROR'}
-                        # An error occurred when trying to create the service/
-                        # establish the connectivity.
-
-                    {'wim_status': 'BUILD'}
-                        # Still trying to create the service, the caller
-                        # needs to wait and check again.
-
-                Additionally ``error_msg``(**str**) and ``wim_info``(**dict**)
-                keys can be used to provide additional status explanation or
-                new information available for the connectivity service.
-        """
-        raise NotImplementedError
-
-    def create_connectivity_service(self, service_type, connection_points,
-                                    **kwargs):
-        """Stablish WAN connectivity between the endpoints
-
-        Arguments:
-            service_type (str): ``ELINE`` (L2), ``ELAN`` (L2), ``ETREE`` (L2),
-                ``L3``.
-            connection_points (list): each point corresponds to
-                an entry point from the DC to the transport network. One
-                connection point serves to identify the specific access and
-                some other service parameters, such as encapsulation type.
-                Represented by a dict as follows::
-
-                    {
-                      "service_endpoint_id": ..., (str[uuid])
-                      "service_endpoint_encapsulation_type": ...,
-                           (enum: none, dot1q, ...)
-                      "service_endpoint_encapsulation_info": {
-                        ... (dict)
-                        "vlan": ..., (int, present if encapsulation is dot1q)
-                        "vni": ... (int, present if encapsulation is vxlan),
-                        "peers": [(ipv4_1), (ipv4_2)]
-                            (present if encapsulation is vxlan)
-                      }
-                    }
-
-              The service endpoint ID should be previously informed to the WIM
-              engine in the RO when the WIM port mapping is registered.
-
-        Keyword Arguments:
-            bandwidth (int): value in kilobytes
-            latency (int): value in milliseconds
-
-        Other QoS might be passed as keyword arguments.
-
-        Returns:
-            tuple: ``(service_id, conn_info)`` containing:
-               - *service_uuid* (str): UUID of the established connectivity
-                  service
-               - *conn_info* (dict or None): Information to be stored at the
-                 database (or ``None``). This information will be provided to
-                 the :meth:`~.edit_connectivity_service` and :obj:`~.delete`.
-                 **MUST** be JSON/YAML-serializable (plain data structures).
-
-        Raises:
-            WimConnectorException: In case of error.
-        """
-        raise NotImplementedError
-
-    def delete_connectivity_service(self, service_uuid, conn_info=None):
-        """Disconnect multi-site endpoints previously connected
-
-        This method should receive as arguments both the UUID and the
-        connection info dict (respectively), as returned by
-        :meth:`~.create_connectivity_service` and
-        :meth:`~.edit_connectivity_service`.
-
-        Arguments:
-            service_uuid (str): UUID of the connectivity service
-            conn_info (dict or None): Information returned by the connector
-                during the service creation and subsequently stored in the
-                database.
-
-        Raises:
-            WimConnectorException: In case of error.
-        """
-        raise NotImplementedError
-
-    def edit_connectivity_service(self, service_uuid, conn_info=None,
-                                  connection_points=None, **kwargs):
-        """Change an existing connectivity service.
-
-        This method's arguments and return value follow the same convention as
-        :meth:`~.create_connectivity_service`.
-
-        Arguments:
-            service_uuid (str): UUID of the connectivity service.
-            conn_info (dict or None): Information previously stored in the
-                database.
-            connection_points (list): If provided, the old list of connection
-                points will be replaced.
-
-        Returns:
-            dict or None: Information to be updated and stored at the
-                database.
-                When ``None`` is returned, no information should be changed.
-                When an empty dict is returned, the database record will be
-                deleted.
-                **MUST** be JSON/YAML-serializable (plain data structures).
-
-        Raises:
-            WimConnectorException: In case of error.
-        """
-        raise NotImplementedError
-
-    def clear_all_connectivity_services(self):
-        """Delete all WAN Links in a WIM.
-
-        This method is intended for debugging only, and should delete all the
-        connections controlled by the WIM, not only the WIM connections that
-        a specific RO is aware of.
-
-        Raises:
-            WimConnectorException: In case of error.
-        """
-        raise NotImplementedError
-
-    def get_all_active_connectivity_services(self):
-        """Provide information about all active connections provisioned by a
-        WIM.
-
-        Raises:
-            WimConnectorException: In case of error.
-        """
-        raise NotImplementedError
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index bda5b8a..0000000
--- a/requirements.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-PyYAML
-bottle
-MySQL-python
-jsonschema
-paramiko
-argcomplete
-requests
-logutils
-python-openstackclient
-python-novaclient
-python-keystoneclient
-python-glanceclient
-python-neutronclient
-networking-l2gw
-python-cinderclient
-pyvcloud==19.1.1
-pyvmomi
-progressbar
-prettytable
-boto
-genisoimage
-untangle
-pyone
-oca
-azure
diff --git a/scripts/python-osm-ro.postinst b/scripts/python-osm-ro.postinst
deleted file mode 100755
index 0f6e5a8..0000000
--- a/scripts/python-osm-ro.postinst
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/bin/bash
-
-##
-# 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.
-#
-# For those usages not covered by the Apache License, Version 2.0 please
-# contact with: OSM_TECH@list.etsi.org
-##
-
-echo "POST INSTALL OSM-RO"
-OSMRO_PATH=`python -c 'import osm_ro; print osm_ro.__path__[0]'`
-#OSMLIBOVIM_PATH=`python -c 'import lib_osm_openvim; print lib_osm_openvim.__path__[0]'`
-
-#Pip packages required for vmware connector
-pip2 install pip==9.0.3
-pip2 install --upgrade pyvcloud==19.1.1
-pip2 install --upgrade progressbar
-pip2 install --upgrade prettytable
-pip2 install --upgrade pyvmomi
-pip2 install --upgrade pyang pyangbind
-pip2 install untangle
-pip2 install pyone
-pip2 install -e git+https://github.com/python-oca/python-oca#egg=oca
-pip2 install azure
-
-# Packages required for fos connector
-pip2 install fog05rest
-
-
-systemctl enable osm-ro.service
-
-#Creation of log folder
-mkdir -p /var/log/osm
-
-#configure arg-autocomplete for this user
-su $SUDO_USER -c 'activate-global-python-argcomplete --user'
-if ! su  $SUDO_USER -c 'grep -q bash_completion.d/python-argcomplete.sh ${HOME}/.bashrc'
-then
-    echo "    inserting .bash_completion.d/python-argcomplete.sh execution at .bashrc"
-    su $SUDO_USER -c 'echo ". ${HOME}/.bash_completion.d/python-argcomplete.sh" >> ~/.bashrc'
-fi
-
-echo '
-To make OSM RO work, you have to install mysql and a database, and finally start osm-ro service'
-echo "     ${OSMRO_PATH}/database_utils/install-db-server.sh # -h for help"
-echo '     service osm-ro start'
-
-
diff --git a/setup.py b/setup.py
deleted file mode 100755
index 5d78ec3..0000000
--- a/setup.py
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/usr/bin/env python
-
-#from distutils.core import setup
-#from distutils.command.install_data import install_data
-from setuptools import setup
-from os import system
-#import glob
-
-_name = 'osm_ro'
-_description = 'OSM Resource Orchestrator'
-_author = 'ETSI OSM'
-_author_email = 'alfonso.tiernosepulveda@telefonica.com'
-_maintainer = 'garciadeblas'
-_maintainer_email = 'gerardo.garciadeblas@telefonica.com'
-_license = 'Apache 2.0'
-_url = 'https://osm.etsi.org/gitweb/?p=osm/RO.git;a=summary'
-_requirements = [
-    "six",  # python 2 x 3 compatibility
-    "PyYAML",
-    "bottle",
-    #"mysqlclient",
-    #"MySQLdb",
-    "jsonschema",
-    "paramiko",
-    "argcomplete",
-    "requests",
-    "logutils",
-    "python-openstackclient",
-    "python-novaclient",
-    "python-keystoneclient",
-    "python-glanceclient",
-    "python-neutronclient",
-    "python-cinderclient",
-    "networking-l2gw",
-    #"pyvcloud",
-    #"progressbar",
-    "prettytable",
-    #"pyvmomi",
-    "boto",
-    #"lib_osm_openvim",
-    #"osm_im",
-    "pycrypto",
-    "netaddr",
-]
-
-setup(name=_name,
-      version_command=('git describe --match v*', 'pep440-git-full'),
-      description = _description,
-      long_description = open('README.rst').read(),
-      author = _author,
-      author_email = _author_email,
-      maintainer = _maintainer,
-      maintainer_email = _maintainer_email,
-      url = _url,
-      license = _license,
-      packages = [_name],
-      #packages = ['osm_ro', 'osm_roclient'],
-      package_dir = {_name: _name},
-      package_data = {_name: ['vnfs/*.yaml', 'vnfs/examples/*.yaml',
-                         'scenarios/*.yaml', 'scenarios/examples/*.yaml',
-                         'instance-scenarios/examples/*.yaml', 'database_utils/*',
-                         'scripts/*']},
-      data_files = [('/etc/osm/', ['osm_ro/openmanod.cfg']),
-                   ('/etc/systemd/system/', ['osm_ro/osm-ro.service']),
-                   ],
-      scripts=['openmanod', 'openmano', 'osm_ro/scripts/service-openmano', 'osm_ro/scripts/openmano-report',
-          'osm_ro/scripts/RO-start.sh'],
-      install_requires=_requirements,
-      include_package_data=True,
-      setup_requires=['setuptools-version-command'],
-      #test_suite='nose.collector',
-      )
-
diff --git a/stdeb.cfg b/stdeb.cfg
deleted file mode 100644
index 3751334..0000000
--- a/stdeb.cfg
+++ /dev/null
@@ -1,6 +0,0 @@
-[DEFAULT]
-Suite: xenial
-XS-Python-Version: >= 2.7
-Maintainer: Gerardo Garcia <gerardo.garciadeblas@telefonica.com>
-Depends: python-pip, libmysqlclient-dev, libssl-dev, libffi-dev, python-argcomplete, python-boto, python-bottle, python-jsonschema, python-logutils, python-cinderclient, python-glanceclient, python-keystoneclient, python-neutronclient, python-networking-l2gw, python-novaclient, python-openstackclient, python-mysqldb, python-lib-osm-openvim, python-osm-im, python-networkx, genisoimage
-
diff --git a/test-docker/Dockerfile-devops b/test-docker/Dockerfile-devops
new file mode 100644
index 0000000..25eb013
--- /dev/null
+++ b/test-docker/Dockerfile-devops
@@ -0,0 +1,65 @@
+##
+# Copyright 2019 ETSI
+#
+# 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.
+##
+
+########################################################################
+
+from ubuntu:18.04
+
+MAINTAINER  Alfonso Tierno <alfonso.tiernosepulveda@telefoncia.com>
+
+RUN apt-get update && apt-get -y install curl software-properties-common git tox python3-pip \
+    && python3 -m pip install --upgrade pip && python3 -m pip install pyangbind
+
+ARG REPOSITORY_BASE=http://osm-download.etsi.org/repository/osm/debian
+ARG RELEASE=ReleaseSIX-daily
+ARG REPOSITORY_KEY=OSM%20ETSI%20Release%20Key.gpg
+ARG REPOSITORY=testing
+
+RUN curl ${REPOSITORY_BASE}/${RELEASE}/${REPOSITORY_KEY} | apt-key add -
+RUN add-apt-repository -y "deb ${REPOSITORY_BASE}/${RELEASE} ${REPOSITORY} IM common openvim" && apt-get update
+
+ARG RO_VERSION
+ARG IM_VERSION
+
+COPY temp /app
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python3-osm-im${IM_VERSION} \
+    && DEBIAN_FRONTEND=noninteractive dpkg -i --force-depends /app/*.deb \
+    && DEBIAN_FRONTEND=noninteractive apt-get  -y -f install
+
+EXPOSE 9090
+
+# Two mysql databases are needed (DB and DB_OVIM). Can be hosted on same or separated containers
+# These ENV must be provided
+ENV RO_DB_HOST=""
+ENV RO_DB_OVIM_HOST=""
+    # if empty RO_DB_HOST is assumed
+
+# These ENV should be provided first time for creating database. It will create and init only if empty!
+ENV RO_DB_ROOT_PASSWORD=""
+ENV RO_DB_OVIM_ROOT_PASSWORD=""
+    # if empty RO_DB_ROOT_PASSWORD is assumed
+
+# These ENV can be provided, but default values are ok
+ENV RO_DB_USER=mano
+ENV RO_DB_OVIM_USER=mano
+ENV RO_DB_PASSWORD=manopw
+ENV RO_DB_OVIM_PASSWORD=manopw
+ENV RO_DB_PORT=3306
+ENV RO_DB_OVIM_PORT=3306
+ENV RO_DB_NAME=mano_db
+ENV RO_DB_OVIM_NAME=mano_vim_db
+
+CMD RO-start.sh
diff --git a/test-docker/test-gen-devops.sh b/test-docker/test-gen-devops.sh
new file mode 100755
index 0000000..3d04c1f
--- /dev/null
+++ b/test-docker/test-gen-devops.sh
@@ -0,0 +1,66 @@
+#!/bin/bash
+
+##
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+
+# Generates the debian packages; and then generates a docker image base on Dockerfile-devops and update a
+# running docker stack with the generated image
+
+HERE=$(dirname $(readlink -f ${BASH_SOURCE[0]}))
+export RO_BASE=$(dirname $HERE)
+
+# clean
+docker rm -f ro_pkg 2>/dev/null && echo docker ro_pkg removed
+rm -rf $HERE/temp/*
+find $RO_BASE  -name "*.pyc" -exec rm {} ";"
+mkdir -p $HERE/temp
+
+echo -e "\n\n[STAGE 1] Builind dockerfile userd for the package generation"
+docker build $RO_BASE -f $RO_BASE/Dockerfile  -t opensourcemano/ro_pkg
+sleep 2
+
+echo "[STAGE 1.1] Generting packages inside docker ro_pkg"
+docker run -d --name ro_pkg opensourcemano/ro_pkg bash -c 'sleep 3600'
+docker cp $RO_BASE ro_pkg:/RO
+docker exec ro_pkg bash -c 'cd /RO;  ./devops-stages/stage-build.sh'
+deb_files=`docker exec ro_pkg bash -c 'ls /RO/deb_dist/'`
+[ -z "$deb_files" ] && echo "No packages generated" >&2 && exit 1
+echo $deb_files
+
+echo -e "\n\n[STAGE 1.2] Print package information and copy to '$HERE/temp/'"
+# print package information and copy to "$HERE/temp/"
+for deb_file in $deb_files ; do
+   echo; echo; echo
+   echo $deb_file info:
+   echo "===========================" 
+   docker cp ro_pkg:/RO/deb_dist/$deb_file $HERE/temp/
+   dpkg -I $HERE/temp/$(basename $deb_file)
+done
+
+# docker rm -f ro_pkg
+echo -e "\n\n[STAGE 2] Building docker image opensourcemano/ro:py3_devops based on debian packages"
+docker build $HERE -f $HERE/Dockerfile-devops  -t opensourcemano/ro:py3_devops ||
+    ! echo "error generating devops dockerfile" >&2 || exit 1
+sleep 2
+# docker run -d --name ro_devops opensourcemano/ro:py3_devops
+# docker run -ti exec ro_devops ro tenant-list  || ! echo "Cannot exec ro client to get server tenants" >&2 || exit 1
+
+echo -e "\n\n[STAGE 3] Update service osm_ro with generated docker image"
+docker service update osm_ro --force --image opensourcemano/ro:py3_devops
+sleep 2
+docker container prune -f
+docker service logs osm_ro
diff --git a/test-docker/test-gen-local.sh b/test-docker/test-gen-local.sh
new file mode 100755
index 0000000..0b9c73e
--- /dev/null
+++ b/test-docker/test-gen-local.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+##
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+
+# Generates a docker image base on Dockerfile-local and update a running docker stack with the generated image
+
+HERE=$(dirname $(readlink -f ${BASH_SOURCE[0]}))
+export RO_BASE=$(dirname $HERE)
+
+echo -e "\n\n[STAGE 1] Building docker image opensourcemano/ro:py3_local based on debian packages"
+docker build $RO_BASE -f $RO_BASE/Dockerfile-local -t opensourcemano/ro:py3_local ||
+    ! echo "error generating local dockerfile" >&2 || exit 1
+sleep 2
+docker service update osm_ro --force --image opensourcemano/ro:py3_local
+sleep 2
+docker container prune -f
+docker service logs osm_ro
diff --git a/tox.ini b/tox.ini
deleted file mode 100644
index e451bb8..0000000
--- a/tox.ini
+++ /dev/null
@@ -1,23 +0,0 @@
-[tox]
-#envlist = py27,py3
-envlist = py27
-toxworkdir={homedir}/.tox
-
-[testenv]
-deps=nose
-     mock
-commands=nosetests
-
-[testenv:flake8]
-basepython = python
-deps = flake8
-# TODO for the moment few files are tested.
-commands = flake8 osm_ro/wim  --max-line-length 120 \
-    --exclude .svn,CVS,.gz,.git,__pycache__,.tox,local,temp,osm_im --ignore W291,W293,E226,E402,W504
-
-[testenv:build]
-basepython = python
-deps = stdeb
-       setuptools-version-command
-commands = python setup.py --command-packages=stdeb.command bdist_deb
-