From: tierno Date: Wed, 13 Sep 2017 12:10:56 +0000 (+0200) Subject: Merge branch 'v2.0' X-Git-Tag: v3.0.0 X-Git-Url: https://osm.etsi.org/gitweb/?a=commitdiff_plain;h=f1bf85be54cd337dc436ceb494c6ad02d46a0261;hp=cbccaab896302e15b1c7e91cfa76033b1be049ff;p=osm%2Fopenvim.git Merge branch 'v2.0' --- diff --git a/Dockerfile b/Dockerfile index 2e05659..7dac9e8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,8 @@ FROM ubuntu:16.04 RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get -y install git build-essential && \ - DEBIAN_FRONTEND=noninteractive apt-get -y install python python-dev python-all python-stdeb fakeroot pypi2deb && \ - DEBIAN_FRONTEND=noninteractive apt-get -y install python-pip libmysqlclient-dev libssl-dev libffi-dev libvirt-dev && \ - DEBIAN_FRONTEND=noninteractive pip install --upgrade pip && \ - DEBIAN_FRONTEND=noninteractive pip install --upgrade setuptools && \ - DEBIAN_FRONTEND=noninteractive apt-get -y install python-argcomplete python-jsonschema python-logutils python-mysqldb python-paramiko python-requests python-yaml python-bottle python-libvirt + DEBIAN_FRONTEND=noninteractive apt-get -y install git make python python-pip debhelper && \ + DEBIAN_FRONTEND=noninteractive pip install -U pip && \ + DEBIAN_FRONTEND=noninteractive pip install -U setuptools setuptools-version-command stdeb + diff --git a/MANIFEST.in b/MANIFEST.in index 3a9e9a9..71cb3ec 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,5 @@ include README.rst -include OPENVIM_VERSION +#include OPENVIM_VERSION include openflow include openvimd include openvim diff --git a/Makefile b/Makefile index bae4fe1..553d349 100644 --- a/Makefile +++ b/Makefile @@ -1,25 +1,36 @@ #!/usr/bin/env bash +.PHONY: all test clean + SHELL := /bin/bash -all: clean build pip install -lite: clean build_lite pip_lite install_lite +all: + $(MAKE) clean_build build + $(MAKE) clean_build openvim + $(MAKE) clean_build build_lite + $(MAKE) clean_build lite + +openvim: package_openvim + +lite: package_lib_openvim -clean_deb: +clean: clean_build rm -rf .build -clean: + +clean_build: rm -rf build find osm_openvim -name '*.pyc' -delete find osm_openvim -name '*.pyo' -delete prepare_lite: - pip install --user --upgrade setuptools + #pip 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/OVIM_VERSION + #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/OVIM_VERSION + cp tox.ini build/ cp MANIFEST.in build/ - sed -i "s/include OPENVIM_VERSION/include OVIM_VERSION/g" build/MANIFEST.in + #sed -i "s/include OPENVIM_VERSION/include OVIM_VERSION/g" build/MANIFEST.in sed -i "s/recursive-include osm_openvim/recursive-include lib_osm_openvim/g" build/MANIFEST.in sed -i "s/include openflow/include openflow-lib/g" build/MANIFEST.in sed -i '/include openvimd/d' build/MANIFEST.in @@ -39,12 +50,13 @@ prepare_lite: sed -i "s/__import__(\"osm_openvim\.\"/__import__(\"lib_osm_openvim\.\"/g" build/lib_osm_openvim/ovim.py prepare: - pip install --user --upgrade setuptools + #pip 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/OPENVIM_VERSION + #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/OPENVIM_VERSION + cp tox.ini build/ cp MANIFEST.in build/ cp README.rst build/ cp setup.py build/ @@ -61,17 +73,19 @@ prepare: build: prepare python -m py_compile build/osm_openvim/*.py + #cd build && tox -e flake8 build_lite: prepare_lite python -m py_compile build/lib_osm_openvim/*.py + #cd build && tox -e flake8 -pip: clean build +pip: build cd build && ./setup.py sdist -pip_lite: clean build_lite +pip_lite: build_lite cd build && ./setup.py sdist -package_openvim: clean prepare +package_openvim: 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_openvim/scripts/python-osm-openvim.postinst deb_dist/osm-openvim*/debian/ @@ -79,15 +93,14 @@ package_openvim: clean prepare mkdir -p .build cp build/deb_dist/python-*.deb .build/ -package_lib: clean prepare_lite +package_lib_openvim: prepare_lite #apt-get install -y python-stdeb - cd build && python setup.py --command-packages=stdeb.command sdist_dsc --with-python2=True - cd build/deb_dist/lib-osm-openvim* && dpkg-buildpackage -rfakeroot -uc -us + #cd build && python setup.py --command-packages=stdeb.command sdist_dsc --with-python2=True + #cd build/deb_dist/lib-osm-openvim* && dpkg-buildpackage -rfakeroot -uc -us + cd build && python setup.py --command-packages=stdeb.command bdist_deb mkdir -p .build cp build/deb_dist/python-*.deb .build/ -package: clean_deb package_openvim package_lib - snap: echo "Nothing to be done yet" diff --git a/devops-stages/stage-build.sh b/devops-stages/stage-build.sh index 8505499..c38c275 100755 --- a/devops-stages/stage-build.sh +++ b/devops-stages/stage-build.sh @@ -1,2 +1,2 @@ #!/bin/sh -make package +make clean all diff --git a/osm_openvim/host_thread.py b/osm_openvim/host_thread.py index 368dcbc..78be1c9 100644 --- a/osm_openvim/host_thread.py +++ b/osm_openvim/host_thread.py @@ -842,7 +842,7 @@ class host_thread(threading.Thread): command = 'sudo ip netns exec {} cat {}'.format(dhcp_namespace, pid_file) content = self.run_command(command, ignore_exit_status=True) dns_pid = content.replace('\n', '') - command = 'sudo ip netns exec {} kill -9 '.format(dhcp_namespace, dns_pid) + command = 'sudo ip netns exec {} kill -9 {}'.format(dhcp_namespace, dns_pid) self.run_command(command, ignore_exit_status=True) except RunCommandException as e: @@ -952,7 +952,7 @@ class host_thread(threading.Thread): command = 'sudo ip link set dev ovim-{} down'.format(str(vlan)) self.run_command(command) - command = 'sudo ifconfig {} down && sudo brctl delbr {}'.format(port_name, port_name) + command = 'sudo ip link delete {} && sudo brctl delbr {}'.format(port_name, port_name) self.run_command(command) return True except RunCommandException as e: @@ -975,14 +975,14 @@ class host_thread(threading.Thread): # Delete ovs veth pair command = 'sudo ip link set dev {} down'.format(br_ovs_name) - self.run_command(command) + self.run_command(command, ignore_exit_status=True) command = 'sudo ovs-vsctl del-port br-int {}'.format(br_ovs_name) self.run_command(command) # Delete br veth pair command = 'sudo ip link set dev {} down'.format(br_tap_name) - self.run_command(command) + self.run_command(command, ignore_exit_status=True) # Delete br veth interface form bridge command = 'sudo brctl delif {} {}'.format(link, br_tap_name) @@ -990,7 +990,7 @@ class host_thread(threading.Thread): # Delete br veth pair command = 'sudo ip link set dev {} down'.format(link) - self.run_command(command) + self.run_command(command, ignore_exit_status=True) return True except RunCommandException as e: @@ -1213,6 +1213,9 @@ class host_thread(threading.Thread): command = 'sudo ip link set dev {} down'.format(ovs_veth_name) self.run_command(command, ignore_exit_status=True) # to end session + command = 'sudo ip link delete {} '.format(ovs_veth_name) + self.run_command(command, ignore_exit_status=True) + command = 'sudo ip netns exec {} ip link set dev {} down'.format(dhcp_namespace, br_veth_name) self.run_command(command, ignore_exit_status=True) @@ -1291,26 +1294,37 @@ class host_thread(threading.Thread): qrouter_ns_router_veth = '{}-vethQB'.format(str(vlan)) command = 'sudo ovs-vsctl del-port br-int {}'.format(qrouter_ovs_veth) - self.run_command(command) + self.run_command(command, ignore_exit_status=True) # down ns veth command = 'sudo ip netns exec {} ip link set dev {} down'.format(ns_qouter, qrouter_ns_veth) - self.run_command(command) + self.run_command(command, ignore_exit_status=True) + + command = 'sudo ip netns exec {} ip link delete {} '.format(ns_qouter, qrouter_ns_veth) + self.run_command(command, ignore_exit_status=True) command = 'sudo ip netns del ' + ns_qouter self.run_command(command) # down ovs veth interface command = 'sudo ip link set dev {} down'.format(qrouter_br_veth) - self.run_command(command) + self.run_command(command, ignore_exit_status=True) # down br veth interface command = 'sudo ip link set dev {} down'.format(qrouter_ovs_veth) - self.run_command(command) + self.run_command(command, ignore_exit_status=True) + + # delete veth interface + command = 'sudo ip link delete {} '.format(link, qrouter_ovs_veth) + self.run_command(command, ignore_exit_status=True) # down br veth interface command = 'sudo ip link set dev {} down'.format(qrouter_ns_router_veth) - self.run_command(command) + self.run_command(command, ignore_exit_status=True) + + # delete veth interface + command = 'sudo ip link delete {} '.format(link, qrouter_ns_router_veth) + self.run_command(command, ignore_exit_status=True) # down br veth interface command = 'sudo brctl delif {} {}'.format(link, qrouter_br_veth) @@ -1344,7 +1358,7 @@ class host_thread(threading.Thread): # Create pait veth command = 'sudo ip link add {} type veth peer name {}'.format(qrouter_ns_veth, qrouter_ovs_veth) - self.run_command(command) + self.run_command(command, ignore_exit_status=True) # up ovs veth interface command = 'sudo ip link set dev {} up'.format(qrouter_ovs_veth) diff --git a/osm_openvim/ovim.py b/osm_openvim/ovim.py index 5650cd5..53a39eb 100755 --- a/osm_openvim/ovim.py +++ b/osm_openvim/ovim.py @@ -43,8 +43,8 @@ import openflow_conn __author__ = "Alfonso Tierno, Leonardo Mirabal" __date__ = "$06-Feb-2017 12:07:15$" -__version__ = "0.5.18-r534" -version_date = "Jun 2017" +__version__ = "0.5.20-r536" +version_date = "Sep 2017" database_version = 21 #needed database schema version HTTP_Bad_Request = 400 @@ -301,13 +301,14 @@ class ovim(): links = net.get('links') if links: links = yaml.safe_load(net.get('links')) - self.launch_dhcp_server(net.get('vlan'), - net.get('dhcp_first_ip'), - net.get('dhcp_last_ip'), - net.get('cidr'), - net.get('gateway_ip'), - dns, - routes) + if net.get('enable_dhcp'): + self.launch_dhcp_server(net.get('vlan'), + net.get('dhcp_first_ip'), + net.get('dhcp_last_ip'), + net.get('cidr'), + net.get('gateway_ip'), + dns, + routes) self.launch_link_bridge_to_ovs(net['vlan'], net.get('gateway_ip'), net.get('cidr'), links, routes) if net["status"] == "ERROR": self.db.update_rows("nets", UPDATE={"status": "ACTIVE", "last_error": None}, @@ -671,11 +672,10 @@ class ovim(): network['routes'] = yaml.safe_dump(network['routes'], default_flow_style=True, width=256) result, content = self.db.new_row('nets', network, True, True) - if result >= 0 and dhcp_integrity: if bridge_net: bridge_net[3] = content - if self.config.get("dhcp_server") and self.config['network_type'] == 'bridge': + if self.config.get("dhcp_server") and self.config['network_type'] == 'bridge': # \ if network["name"] in self.config["dhcp_server"].get("nets", ()): self.config["dhcp_nets"].append(content) self.logger.debug("dhcp_server: add new net", content) @@ -784,6 +784,7 @@ class ovim(): :param network_id: network id :return: """ + net_data = self.show_network(network_id) # delete from the data base result, content = self.db.delete_row('nets', network_id) @@ -797,7 +798,18 @@ class ovim(): break if self.config.get("dhcp_server") and network_id in self.config["dhcp_nets"]: self.config["dhcp_nets"].remove(network_id) - return content + + if net_data.get('enable_dhcp'): + dhcp_path = self.config['ovs_controller_file_path'] + dhcp_controller = self.get_dhcp_controller() + dhcp_controller.delete_dhcp_server(net_data['vlan'], network_id, dhcp_path) + dhcp_controller.delete_dhcp_port(net_data['vlan'], network_id, dhcp_path) + links = yaml.load(net_data.get('links')) + if links: + links = yaml.load(net_data.get('links')) + self.delete_link_bridge_to_ovs(net_data['vlan'], links) + + return content else: raise ovimException("Error deleting network '{}': {}".format(network_id, content), -result) @@ -1349,6 +1361,8 @@ class ovim(): map['switch_dpid'] = switch_dpid if region: map['region'] = region + if map.get("pci"): + map["pci"] = map["pci"].lower() for of_map in of_maps: result, uuid = self.db.new_row('of_port_mappings', of_map, True) diff --git a/osm_openvim/vim_schema.py b/osm_openvim/vim_schema.py index 9440872..697b4e9 100644 --- a/osm_openvim/vim_schema.py +++ b/osm_openvim/vim_schema.py @@ -32,27 +32,36 @@ __date__ ="$10-jul-2014 12:07:15$" # path_schema = {"type": "string", "maxLength": 255, "pattern": "^(\.){0,2}(/[^/\"':{}\(\)]+)+$"} -http_schema={"type":"string", "pattern":"^https?://[^'\"=]+$"} -port_schema={"type":"integer","minimum":1,"maximun":65534} -ip_schema={"type":"string","pattern":"^([0-9]{1,3}.){3}[0-9]{1,3}$"} -cidr_schema={"type":"string","pattern":"^([0-9]{1,3}.){3}[0-9]{1,3}/[0-9]{1,2}$"} -name_schema={"type" : "string", "minLength":1, "maxLength":255, "pattern" : "^[^,;()'\"]+$"} -nameshort_schema={"type" : "string", "minLength":1, "maxLength":64, "pattern" : "^[^,;()'\"]+$"} -nametiny_schema={"type" : "string", "minLength":1, "maxLength":12, "pattern" : "^[^,;()'\"]+$"} -xml_text_schema={"type" : "string", "minLength":1, "maxLength":1000, "pattern" : "^[^']+$"} -description_schema={"type" : ["string","null"], "maxLength":255, "pattern" : "^[^'\"]+$"} -id_schema_fake = {"type" : "string", "minLength":2, "maxLength":36 } #"pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" -id_schema = {"type" : "string", "pattern": "^[a-fA-F0-9]{8}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$"} -pci_schema={"type":"string", "pattern":"^[0-9a-fA-F]{4}(:[0-9a-fA-F]{2}){2}\.[0-9a-fA-F]$"} -bandwidth_schema={"type":"string", "pattern" : "^[0-9]+ *([MG]bps)?$"} -integer0_schema={"type":"integer","minimum":0} -integer1_schema={"type":"integer","minimum":1} -vlan_schema={"type":"integer","minimum":1,"maximun":4095} -vlan1000_schema={"type":"integer","minimum":1000,"maximun":4095} -mac_schema={"type":"string", "pattern":"^[0-9a-fA-F][02468aceACE](:[0-9a-fA-F]{2}){5}$"} #must be unicast LSB bit of MSB byte ==0 -net_bind_schema={"oneOf":[{"type":"null"},{"type":"string", "pattern":"^(default|((bridge|macvtap):[0-9a-zA-Z\.\-]{1,50})|openflow:[/0-9a-zA-Z\.\-]{1,50}(:vlan)?)$"}]} -yes_no_schema={"type":"string", "enum":["yes", "no"]} -log_level_schema={"type":"string", "enum":["DEBUG", "INFO", "WARNING","ERROR","CRITICAL"]} +http_schema = {"type": "string", "pattern": "^https?://[^'\"=]+$"} +port_schema = {"type": "integer","minimum": 1, "maximun": 65534} +ip_schema = {"type": "string", "pattern": "^([0-9]{1,3}.){3}[0-9]{1,3}$"} +cidr_schema = {"type": "string", "pattern": "^([0-9]{1,3}.){3}[0-9]{1,3}/[0-9]{1,2}$"} +name_schema = {"type": "string", "minLength": 1, "maxLength": 255, "pattern": "^[^,;()'\"]+$"} +nameshort_schema = {"type": "string", "minLength": 1, "maxLength": 64, "pattern": "^[^,;()'\"]+$"} +nametiny_schema = {"type": "string", "minLength": 1, "maxLength": 12, "pattern": "^[^,;()'\"]+$"} +xml_text_schema = {"type": "string", "minLength": 1, "maxLength": 1000, "pattern": "^[^']+$"} +description_schema = {"type": ["string", "null"], "maxLength": 255, "pattern": "^[^'\"]+$"} +id_schema_fake = {"type": "string", "minLength": 2, "maxLength": 36} + # "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" +id_schema = {"type": "string", "pattern": "^[a-fA-F0-9]{8}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$"} +pci_schema = {"type": "string", "pattern": "^[0-9a-fA-F]{4}(:[0-9a-fA-F]{2}){2}\.[0-9a-fA-F]$"} +# used by VIO neutron-port-show -::.- +pci_extended_schema = {"type": "string", "pattern": "^([0-9a-fA-F]{4}-)?[0-9a-fA-F]{4}(:[0-9a-fA-F]{2}){2}" + "\.[0-9a-fA-F](-[0-9a-fA-F]{3})?$"} +bandwidth_schema = {"type": "string", "pattern": "^[0-9]+ *([MG]bps)?$"} +integer0_schema = {"type": "integer", "minimum": 0} +integer1_schema = {"type": "integer", "minimum": 1} +vlan_schema = {"type": "integer", "minimum": 1, "maximun": 4095} +vlan1000_schema = {"type": "integer", "minimum": 1000, "maximun": 4095} +mac_schema = {"type": "string", "pattern": "^[0-9a-fA-F][02468aceACE](:[0-9a-fA-F]{2}){5}$"} + # must be unicast LSB bit of MSB byte ==0 +net_bind_schema = {"oneOf": [ + {"type": "null"}, + {"type": "string", "pattern": + "^(default|((bridge|macvtap):[0-9a-zA-Z\.\-]{1,50})|openflow:[/0-9a-zA-Z\.\-]{1,50}(:vlan)?)$"} +]} +yes_no_schema = {"type": "string", "enum": ["yes", "no"]} +log_level_schema = {"type": "string", "enum":["DEBUG", "INFO", "WARNING","ERROR","CRITICAL"]} config_schema = { "title": "main configuration information schema", @@ -765,7 +774,7 @@ of_port_new_schema = { "ofc_id": id_schema, "region": nameshort_schema, "compute_node": nameshort_schema, - "pci": pci_schema, + "pci": pci_extended_schema, "switch_dpid": nameshort_schema, "switch_port": nameshort_schema, "switch_mac": mac_schema diff --git a/scripts/install-openvim.sh b/scripts/install-openvim.sh index feaee4e..b25a6b0 100755 --- a/scripts/install-openvim.sh +++ b/scripts/install-openvim.sh @@ -232,8 +232,8 @@ then "#################################################################\n"\ "##### INSTALL PYTHON PACKAGES #####\n"\ "#################################################################" - [ "$_DISTRO" == "Ubuntu" ] && install_packages "python-yaml python-libvirt python-bottle python-mysqldb python-jsonschema python-paramiko python-argcomplete python-requests python-netaddr" - [ "$_DISTRO" == "CentOS" -o "$_DISTRO" == "Red" ] && install_packages "PyYAML libvirt-python MySQL-python python-jsonschema python-paramiko python-argcomplete python-requests python-netaddr" + [ "$_DISTRO" == "Ubuntu" ] && install_packages "python-yaml python-libvirt python-bottle python-mysqldb python-jsonschema python-paramiko python-argcomplete python-requests python-netaddr python-pexpect" + [ "$_DISTRO" == "CentOS" -o "$_DISTRO" == "Red" ] && install_packages "PyYAML libvirt-python MySQL-python python-jsonschema python-paramiko python-argcomplete python-requests python-netaddr python-pexpect" # The only way to install python-bottle on Centos7 is with easy_install or pip [ "$_DISTRO" == "CentOS" -o "$_DISTRO" == "Red" ] && easy_install -U bottle diff --git a/setup.py b/setup.py index 6856ff1..4d4073a 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,6 @@ from setuptools import setup __name = 'osm_openvim' -__version = open('OPENVIM_VERSION').read().strip() __description = 'OSM Openvim' __author = 'ETSI OSM' __author_email = 'alfonso.tiernosepulveda@telefonica.com' @@ -13,7 +12,7 @@ __license = 'Apache 2.0' __url = 'https://osm.etsi.org/gitweb/?p=osm/openvim.git;a=summary' _req = [ - "asn1crypto", + #"asn1crypto", "cffi", "enum34", "functools32", @@ -34,9 +33,12 @@ _req = [ "requestsexceptions", "netaddr", "bottle", - "MySQL-python", + #"MySQL-python", + #"mysqlclient", "paramiko", - "libvirt-python" + "libvirt-python", + "pytest", + "pexpect" ] __scripts__ = ['openflow', @@ -50,7 +52,7 @@ __scripts__ = ['openflow', 'osm_openvim/scripts/get_dhcp_lease.sh'] setup(name=__name, - version=__version, + version_command=('git describe', 'pep440-git'), description=__description, long_description=__description, author=__author, @@ -67,7 +69,8 @@ setup(name=__name, data_files = [('/etc/osm/', ['osm_openvim/openvimd.cfg']), ('/etc/systemd/system/', ['osm_openvim/osm-openvim.service']), ], - install_requires=_req + install_requires=_req, + setup_requires=['setuptools-version-command'], ) diff --git a/setup_lite.py b/setup_lite.py index 9d2b2ef..7bb1c79 100755 --- a/setup_lite.py +++ b/setup_lite.py @@ -3,7 +3,6 @@ from setuptools import setup __name = 'lib_osm_openvim' -__version = open('OVIM_VERSION').read().strip() __description = 'OSM Openvim library' __author = 'ETSI OSM' __author_email = 'alfonso.tiernosepulveda@telefonica.com' @@ -13,7 +12,7 @@ __license = 'Apache 2.0' __url = 'https://osm.etsi.org/gitweb/?p=osm/openvim.git;a=summary' _req = [ - "asn1crypto", + #"asn1crypto", "cffi", "enum34", "functools32", @@ -34,14 +33,15 @@ _req = [ "requestsexceptions", "netaddr", "bottle", - "MySQL-python", - "paramiko", + #"MySQL-python", + #"mysqlclient", + "paramiko" ] __scripts__ = ['openflow-lib'] setup(name=__name, - version=__version, + version_command=('git describe', 'pep440-git'), description=__description, long_description=__description, author=__author, @@ -55,7 +55,8 @@ setup(name=__name, scripts=__scripts__, package_data={'lib_osm_openvim': ['*']}, include_package_data=True, - install_requires=_req + install_requires=_req, + setup_requires=['setuptools-version-command'], ) diff --git a/test/PY_TEST_README.rst b/test/PY_TEST_README.rst new file mode 100644 index 0000000..2480844 --- /dev/null +++ b/test/PY_TEST_README.rst @@ -0,0 +1,23 @@ +For launch openvim pytest regresion: + + pytest -v -s test/test_openvim_inf.py --config=test/test_openvim_fake.yaml + +The regresion must be launch from an user included in the visudo. +If the regression will be use real infrastructure (fake_mode=False) create a new yaml or modify +the existing template -> test/test_openvim_fake.yaml + + +test.yaml example: + +--- +host: + host_1: + host_2: + host_n: +tenant: test/tenants/test_tenant.yaml +flavor: test/flavors/cirros_flavor.yaml +image: +server: test/servers/cirros_server_template.yaml +net: test/networks/net-example5.yaml +fake_mode: # depend on openvimd.cfg mode (test,normal, host only, OF only, development) +create_inf: # Create host and mgmt net if True, if False host and mgmt net need to be precreated. diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/conftest.py b/test/conftest.py new file mode 100644 index 0000000..2ad3e53 --- /dev/null +++ b/test/conftest.py @@ -0,0 +1,6 @@ +import os + +def pytest_addoption(parser): + parser.addoption('--config', + help='Indicate tests are run on CI server') + os.environ['OPENVIM_ROOT_FOLDER'] = os.getcwd() diff --git a/test/fixtures/__init__.py b/test/fixtures/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/post/__init__.py b/test/fixtures/post/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/post/post_fixtures_delete.py b/test/fixtures/post/post_fixtures_delete.py new file mode 100644 index 0000000..c2213bd --- /dev/null +++ b/test/fixtures/post/post_fixtures_delete.py @@ -0,0 +1,126 @@ +import pytest +import time +from ...lib.test_utils import * + + +@pytest.fixture(autouse=True) +def post_install_service(): + """ + Fixture to be executed before test + :param request: argument for a fixture... can be a list, dict, etc + :param request: + :return: + """ + yield post_install_service + print "Stoping service openvim " + service_path = os.path.join(os.environ['OPENVIM_ROOT_FOLDER'], 'scripts', 'service-openvim') + execute_local("{} stop".format(service_path)) + + +@pytest.fixture() +def post_delete_server(request): + """ + Fixture to be executed before test + :param request: argument for a fixture... can be a list, dict, etc + :param request: + :return: + """ + + yield post_delete_server + + if hasattr(request, 'config'): + config_path = request.config.getoption('config') + config = get_config(config_path) + + if config['create_inf']: + vm_id = os.environ['OPENVIM_VM'] + openvim_path = os.path.join(os.environ['OPENVIM_ROOT_FOLDER'], 'openvim') + execute_local("{} vm-delete {}".format(openvim_path, vm_id)) + + +@pytest.fixture() +def post_delete_net(request): + """ + Fixture to be executed before test + :param request: argument for a fixture... can be a list, dict, etc + :param request: + :return: + """ + + yield post_delete_net + + if hasattr(request, 'config'): + config_path = request.config.getoption('config') + config = get_config(config_path) + if config['create_inf']: + net_id = os.environ['OPENVIM_TEST_MGMT_NET'] + openvim_path = os.path.join(os.environ['OPENVIM_ROOT_FOLDER'], 'openvim') + execute_local("{} net-delete -f {}".format(openvim_path, net_id)) + + +@pytest.fixture() +def post_delete_vm(): + """ + Fixture to be executed after test + :return: + """ + yield post_delete_vm + # destroy vm + openvim_path = os.path.join(os.environ['OPENVIM_ROOT_FOLDER'], 'openvim') + out = execute_local('{} vm-delete -f'.format(openvim_path)) + + +@pytest.fixture() +def post_delete_flavor(): + """ + Fixture to be executed before test + :param request: argument for a fixture... can be a list, dict, etc + :param request: + :return: + """ + + yield post_delete_flavor + + flavor_id = os.environ['OPENVIM_TEST_FLAVOR'] + openvim_path = os.path.join(os.environ['OPENVIM_ROOT_FOLDER'], 'openvim') + execute_local("{} flavor-delete -f {}".format(openvim_path, flavor_id)) + + +@pytest.fixture() +def post_delete_image(): + """ + Fixture to be executed before test + :param request: argument for a fixture... can be a list, dict, etc + :param request: + :return: + """ + + yield post_delete_image + + img_id = os.environ['OPENVIM_TEST_IMAGE'] + openvim_path = os.path.join(os.environ['OPENVIM_ROOT_FOLDER'], 'openvim') + execute_local("{} image-delete -f {}".format(openvim_path, img_id)) + + +@pytest.fixture() +def post_delete_host(request): + """ + Fixture to be executed before test + :param request: argument for a fixture... can be a list, dict, etc + :param request: + :return: + """ + + yield post_delete_host + + if hasattr(request, 'config'): + config_path = request.config.getoption('config') + config = get_config(config_path) + if config['create_inf']: + host_ids = search_host_in_env_var() + for host_ids in host_ids: + openvim_path = os.path.join(os.environ['OPENVIM_ROOT_FOLDER'], 'openvim') + execute_local("{} host-remove -f {}".format(openvim_path, os.environ[host_ids])) + time.sleep(30) + + diff --git a/test/fixtures/pre/__init__.py b/test/fixtures/pre/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/pre/pre_fixtures_create.py b/test/fixtures/pre/pre_fixtures_create.py new file mode 100644 index 0000000..2ad733e --- /dev/null +++ b/test/fixtures/pre/pre_fixtures_create.py @@ -0,0 +1,168 @@ +import pytest +import os +from ...lib.ssh import * +from ...lib.test_utils import * + + +@pytest.fixture(autouse=True) +def pre_launch_openvim_service(): + """ + Fixture to be executed before test + :param request: argument for a fixture... can be a list, dict, etc + :param request: + :return: + """ + service_path = os.path.join(os.environ['OPENVIM_ROOT_FOLDER'], 'scripts', 'service-openvim') + + execute_local('{} stop'.format(service_path)) + print "launching service openvim" + execute_local('{} start'.format(service_path)) + out = execute_local('{} -h '.format(service_path)) + assert out + +@pytest.fixture() +def pre_create_flavor(request): + """ + Fixture to be executed before test + :param request: argument for a fixture... can be a list, dict, etc + :param request: + :return: + """ + if hasattr(request, 'config'): + config_path = request.config.getoption('config') + config = get_config(config_path) + flavor = config['flavor'] + + openvim_path = os.path.join(os.environ['OPENVIM_ROOT_FOLDER'], 'openvim') + + flavor_id = execute_local("{} flavor-create {}".format(openvim_path, flavor)) + flavor_id = parse_uuid(flavor_id) + assert flavor_id + os.environ['OPENVIM_TEST_FLAVOR'] = flavor_id + + +@pytest.fixture() +def pre_create_host(request): + """ + Fixture to be executed before test + :param request: argument for a fixture... can be a list, dict, etc + :param request: + :return: + """ + if hasattr(request, 'config'): + config_path = request.config.getoption('config') + config = get_config(config_path) + + if config['create_inf']: + hosts = config['host'] + counter = 0 + for key, value in hosts.iteritems(): + openvim_path = os.path.join(os.environ['OPENVIM_ROOT_FOLDER'], 'openvim') + + host_id = execute_local("{} host-add {}".format(openvim_path, value)) + host_id = parse_uuid(host_id) + assert host_id + os.environ['OPENVIM_TEST_HOST_' + str(counter)] = host_id + counter += 1 + + +@pytest.fixture() +def pre_create_image(request): + """ + Fixture to be executed before test + :param request: argument for a fixture... can be a list, dict, etc + :param request: + :return: + """ + if hasattr(request, 'config'): + config_path = request.config.getoption('config') + config = get_config(config_path) + img = config['image'] + + openvim_path = os.path.join(os.environ['OPENVIM_ROOT_FOLDER'], 'openvim') + image_id = execute_local("{} image-create {}".format(openvim_path, img)) + image_id = parse_uuid(image_id) + assert image_id + os.environ['OPENVIM_TEST_IMAGE'] = image_id + + +@pytest.fixture() +def pre_create_image(request): + """ + Fixture to be executed before test + :param request: argument for a fixture... can be a list, dict, etc + :param request: + :return: + """ + if hasattr(request, 'config'): + config_path = request.config.getoption('config') + config = get_config(config_path) + img = config['image'] + openvim_path = os.path.join(os.environ['OPENVIM_ROOT_FOLDER'], 'openvim') + image_id = execute_local("{} image-create {}".format(openvim_path, img)) + image_id = parse_uuid(image_id) + assert image_id + os.environ['OPENVIM_TEST_IMAGE'] = image_id + + +@pytest.fixture() +def pre_create_net(request): + """ + Fixture to be executed before test + :param request: argument for a fixture... can be a list, dict, etc + :return: + """ + if hasattr(request, 'config'): + config_path = request.config.getoption('config') + config = get_config(config_path) + if config['create_inf']: + net_yaml = config['net'] + openvim_path = os.path.join(os.environ['OPENVIM_ROOT_FOLDER'], 'openvim') + net_id = execute_local("{} net-create {}".format(openvim_path, net_yaml)) + net_id = parse_uuid(net_id) + assert net_id + + vlan = execute_local("{} net-list {} -vvv | grep provider:vlan:".format(openvim_path, net_id)) + vlan = vlan.replace('provider:vlan:','') + vlan = vlan.replace(' ', '') + vlan = vlan.replace('\n', '') + + os.environ['OPENVIM_TEST_MGMT_NET'] = net_id + os.environ['OPENVIM_TEST_MGMT_NET_VLAN'] = vlan + + +@pytest.fixture() +def pre_create_tenant(request): + """ + Fixture to be executed before test + :param request: argument for a fixture... can be a list, dict, etc + :param monkeypatch: + :return: + """ + + if hasattr(request, 'config'): + config_path = request.config.getoption('config') + config = get_config(config_path) + tenant_yaml = config['tenant'] + openvim_path = os.path.join(os.environ['OPENVIM_ROOT_FOLDER'], 'openvim') + + tenant_id = execute_local("{} tenant-create {}".format(openvim_path, tenant_yaml)) + tenant_id = parse_uuid(tenant_id) + assert tenant_id + os.environ['OPENVIM_TENANT'] = tenant_id + + +@pytest.fixture() +def pre_init_db(request): + """ + Fixture to be executed before test + :param request: argument for a fixture... can be a list, dict, etc + :param request: + :return: + """ + if hasattr(request, 'config'): + config_path = request.config.getoption('config') + config = get_config(config_path) + if config['create_inf']: + init_db_path = os.path.join(os.environ['OPENVIM_ROOT_FOLDER'], 'database_utils', 'init_vim_db.sh') + execute_local('{}'.format(init_db_path)) diff --git a/test/flavors/cirros_flavor.yaml b/test/flavors/cirros_flavor.yaml new file mode 100644 index 0000000..aacb0cf --- /dev/null +++ b/test/flavors/cirros_flavor.yaml @@ -0,0 +1,67 @@ +## +# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U. +# 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: nfvlabs@tid.es +## + + +flavor: + name: flavor-cirros + description: flavor-cirros + # cloud type requirements + ram: 1024 # Memory in MB. Ignored if provided 'memory' at 'extended' + vcpus: 1 # Number of cpus. Ignored if provided at 'extended' + + # NFV type requirements + # allocating EXCLUSIVE resoureces in the same NUMA node. + # extended: # optional + # processor_ranking: 100 # minimal processor family. Not used in current version + # numas: # list of numa set. Only one supported in current version + # - memory: 2 # GByte of huge pages at this numa + + #Choose among one of "cores", "paired-threads", "threads" + #paired-threads: 2 # Cores with two paired hyper threads + #paired-threads-id: [[0,1],[2,3],[4,5],[6,7],[8,9]] # Guess pinning. By default follows incremental order + #threads: 10 # threads awereness of the hyperthreading + ##threads-id: [0,1,2,3,4,5,6,7,8,9] #Optional. Guess pinning + #cores: 5 # Complete cores, without hyperthreading. VIM ensures the other paired thread is idle + ##cores-id: [0,1,2,3,4] # Optional. Guess pinning of cores + + #Optional: Dataplane needed interfaces +# interfaces: +# - name: xe0 # Optional. User friendly name +# vpci: "0000:00:10.0" # Optional. Guess PCI +# bandwidth: 10 Gbps # Needed minimun bandwidth +# dedicated: "yes" # "yes"(passthrough), "no"(sriov with vlan tags), "yes:sriov"(sriovi, but exclusive and without vlan tag) +# - name: xe1 +# vpci: "0000:00:11.0" +# bandwidth: 10 Gbps +# dedicated: "no" + + #Optional: List of extra devices +# devices: # order determines device letter asignation (hda, hdb, ...) +# - type: disk # "disk","cdrom","xml","usb" +# imageRef: 37598e34-ccb3-11e4-a996-52540030594e # UUID of an image, only for disk,cdrom,xml + # vpci: "0000:00:03.0" # Optional, not for disk or cdrom + # xml: 'Only for type xml: a XML described device xml text. Do not use single quotes inside + # The following words, if found, will be replaced: + # __file__ by image path, (imageiRef must be provided) + # __format__ by qcow2 or raw (imageRef must be provided) + # __dev__ by device letter (b, c, d ...) + # __vpci__ by vpci (vpci must be provided) + diff --git a/test/images/cirros_image.yaml b/test/images/cirros_image.yaml new file mode 100644 index 0000000..a771d55 --- /dev/null +++ b/test/images/cirros_image.yaml @@ -0,0 +1,33 @@ +## +# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U. +# 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: nfvlabs@tid.es +## + + +image: + name: image-cirros-test + description: image-cirros + path: /opt/VNF/images/cirros-0.3.5-x86_64-disk.img + metadata: # Optional extra metadata of the image. All fields are optional + use_incremental: "yes" # "yes" by default, "no" Deployed using a incremental qcow2 image + #vpci: "0000:10:00.0" #requiered PCI at guess + os_distro: cirros # operating system distribution + os_type: linux # operating system type "linux" by default, "windows" + os_version: "7" # operating system version + bus: "ide" # By default "virtio" for linux, "ide" for windows diff --git a/test/lib/__init__.py b/test/lib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/lib/config_parser.py b/test/lib/config_parser.py new file mode 100644 index 0000000..1981fce --- /dev/null +++ b/test/lib/config_parser.py @@ -0,0 +1,15 @@ +import yaml + + +def get_config(file): + """ + Parse test config file + :param file: + :return: + """ + with open(file, 'r') as stream: + try: + return yaml.load(stream) + except yaml.YAMLError as exc: + print(exc) + diff --git a/test/lib/ssh.py b/test/lib/ssh.py new file mode 100644 index 0000000..5480483 --- /dev/null +++ b/test/lib/ssh.py @@ -0,0 +1,126 @@ +import subprocess +import pexpect + + +def execute_local(cmd): + """ + Execute a command in locally + :param cmd: command to be executed + :return: + """ + + print "execute_local cmd = {}".format(cmd) + p = subprocess.Popen(['bash', "-c", cmd], stdout=subprocess.PIPE) + out = p.stdout.read() + print "execute_local result = {}".format(out) + return out + + +def execute_namespace(vlan, cmd): + """ + Execute a command inside a namespace created by openvim + :param vlan: namespace id + :param cmd: command to be executed + :return: + """ + + n_cmd = 'sudo ip netns exec {}-qrouter {} '.format(vlan, cmd) + return execute_local(n_cmd) + + +def ping_ok(vlan_id, ip, retries=200): + """ + + :param vlan_id: namespace id + :param ip: vm ip to be pinged + :param retries: retries, by default 200 + :return: + """ + print 'waiting for vm to be active vm with ip = {}'.format(ip) + for i in xrange(retries): + try: + subprocess.check_output(['bash', "-c", "sudo ip netns exec {}-qrouter ping -c 1 {}".format(vlan_id, ip)]) + return True + except Exception, e: + pass + return False + + +def ping_ok_btw_2_vms(vlan_id, ip_1, ip_2, retires=8): + """ + Check net connectivity between to VM + :param vlan_id: namepsace id + :param ip_1: first vm ip + :param ip_2: second vm ip + :param retires: + :return: + """ + for i in xrange(retires): + + try: + ns_cmd = 'sudo ip netns exec {}-qrouter '.format(vlan_id) + cmd = ns_cmd + ' ssh -oStrictHostKeyChecking=no cirros@{} "ping -c 1 {}"'.format(ip_1, ip_2) + child = pexpect.spawn(cmd) + child.expect('.*assword*') + child.sendline('cubswin:)') + child.sendline('cubswin:)') + + cmd = ns_cmd + ' ssh -oStrictHostKeyChecking=no cirros@{} "ping -c 1 {}"'.format(ip_2, ip_1) + child = pexpect.spawn(cmd) + child.expect('.*assword*') + child.sendline('cubswin:)') + child.sendline('cubswin:)') + + except EOFError as e: + if i == retires: + return False + pass + + return True + + +def copy_rsa_keys_into_vm(vlan_id, ip, rsa_key_path): + """ + copy an RSA key given by the user to a vm + :param vlan_id: + :param ip: + :param rsa_key_path: + :return: + """ + + try: + execute_local('sudo ssh-keygen -f "/root/.ssh/known_hosts" -R {}'.format(ip)) + cmd = 'sudo ip netns exec {}-qrouter ssh-copy-id -i {} ' \ + '-oStrictHostKeyChecking=no -f cirros@{}'.format(vlan_id, rsa_key_path + '.pub', ip) + + print 'copy_rsa_keys_into_vm = ' + cmd + child = pexpect.spawn(cmd) + child.expect('.*assword*') + child.sendline('cubswin:)') + child.sendline('cubswin:)') + return True + except EOFError as e: + return False + + +def execute_check_output(vlan_id, cmd): + """ + Execute a command inside a namespace and raise an expection in case of command fail + :param vlan_id: namepsace id + :param cmd: command + :return: + """ + try: + cmd = "sudo ip netns exec {}-qrouter {}".format(vlan_id, cmd) + print "execute_check_output = {}".format(cmd) + subprocess.check_output(['bash', "-c", cmd]) + return True + except Exception, e: + print "error execute_check_output" + return False + + + + + + diff --git a/test/lib/test_utils.py b/test/lib/test_utils.py new file mode 100644 index 0000000..bf09899 --- /dev/null +++ b/test/lib/test_utils.py @@ -0,0 +1,113 @@ +import yaml +import re +import os +from string import Template +from ssh import * + + +def save_tmp_yaml(name, data): + """ + Save a yaml file into a file to be declare in openvim + :param name: file name + :param data: + :return: + """ + with open(name, "w") as text_file: + text_file.write(data) + + +def delete_tmp_yaml(name): + """ + Delete yaml form Filesystem + :param name: File name + :return: + """ + execute_local('rm {}'.format(name)) + + +def search_host_in_env_var(): + """ + Search for OPENVIM_TEST_HOST_X env var declare by pre_create_host fixture with the host id after creation. + :return: All env vars founded + """ + return search('OPENVIM_TEST_HOST_') + + +def template_substitute(file_path, values): + """ + Modify a Yaml template with values. + :param file_path: template file + :param values: values to be substituted + :return: a string with the file content modified + """ + with open(file_path, 'r') as server_yaml: + template = Template(server_yaml.read()) + server_yaml = template.safe_substitute(values) + return server_yaml + + +def search(reg_ex): + """ + Search for environment vars. + :param reg_ex: regular expresion to be applied during the search + :return: return results + """ + result = {} + for key in os.environ: + if reg_ex in key: + result[key] = os.environ[key] + return result + + +def parse_uuid(data): + """ + Parse an UUID value from a string given. + :param data: String to be evaluated + :return: the uuid value + """ + match = re.compile(r'[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}', re.I).findall(data) + if match: + data = match[0].replace(' ', '') + data = data.replace('\n', '') + return data + else: + return [] + + +def get_config(data): + """ + Parse test config file + :param data: config file path + :return: config dict + """ + with open(data, 'r') as stream: + try: + return yaml.load(stream) + except yaml.YAMLError as exc: + print(exc) + + +def get_vm_ip(vm_id): + """ + Parse vm id IP from openvim client. + :param vm_id: vm id + :return: IP value + """ + openvim_path = os.path.join(os.environ['OPENVIM_ROOT_FOLDER'], 'openvim') + ip = execute_local("{} vm-list {} -vvv | grep ip_address:".format(openvim_path, vm_id)) + ip = ip.replace('ip_address:', '') + ip = ip.replace(' ', '') + return ip + + +def get_net_status(net_id): + """ + Parse a net status from openvim client + :param net_id: network id + :return: + """ + openvim_path = os.path.join(os.environ['OPENVIM_ROOT_FOLDER'], 'openvim') + net_status = execute_local("{} net-list {} -vvv | grep status:".format(openvim_path, net_id)) + net_status = net_status.replace('status:', '') + net_status = net_status.replace(' ', '') + return net_status diff --git a/test/servers/cirros_server_template.yaml b/test/servers/cirros_server_template.yaml new file mode 100644 index 0000000..1b1ae50 --- /dev/null +++ b/test/servers/cirros_server_template.yaml @@ -0,0 +1,35 @@ +## +# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U. +# 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. +# +## + +server: + name: vm-test # name + description: vm-cirros # Optional user description + imageRef: $OPENVIM_TEST_IMAGE + flavorRef: $OPENVIM_TEST_FLAVOR + networks: # List of control plane interfaces, Optional + - name: mgmt #friendly user name + #vpci: "0000:00:0a.0" #Optional guess PCI + uuid: $OPENVIM_TEST_MGMT_NET + #mac_address: #guess concrete mac address, by default one is asigned + #model: "virtio","e1000","ne2k_pci","pcnet","rtl8139", By default auto, normally virtio + start: "yes" # "yes","no","paused". By default it is started upon creted + hostId: $HOST_ID + + # allocating EXCLUSIVE resoureces in the same NUMA node. + # If provided, it overrides extended values at flavor diff --git a/test/tenants/test_tenant.yaml b/test/tenants/test_tenant.yaml new file mode 100644 index 0000000..31ed219 --- /dev/null +++ b/test/tenants/test_tenant.yaml @@ -0,0 +1,25 @@ +## +# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U. +# 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: nfvlabs@tid.es +## + + +tenant: + name: test-tenant + description: tenant for testing purpouse diff --git a/test/test_openvim_fake.yaml b/test/test_openvim_fake.yaml new file mode 100644 index 0000000..a303a4c --- /dev/null +++ b/test/test_openvim_fake.yaml @@ -0,0 +1,10 @@ +host: + host_1: test/hosts/host-example0.yaml + host_2: test/hosts/host-example1.yaml +tenant: test/tenants/test_tenant.yaml +flavor: test/flavors/cirros_flavor.yaml +image: test/images/cirros_image.yaml +server: test/servers/cirros_server_template.yaml +net: test/networks/net-example5.yaml +fake_mode: False +create_inf: True diff --git a/test/test_openvim_inf.py b/test/test_openvim_inf.py new file mode 100644 index 0000000..8e9bd3a --- /dev/null +++ b/test/test_openvim_inf.py @@ -0,0 +1,194 @@ +import pytest +import time +from fixtures.pre.pre_fixtures_create import * +from fixtures.post.post_fixtures_delete import * +from lib.ssh import * +from lib.test_utils import * + + +@pytest.mark.usefixtures('pre_init_db', 'pre_create_host', 'pre_create_tenant', 'pre_create_net', 'pre_create_image', + 'pre_create_flavor', 'post_delete_net', 'post_delete_host') +def test_osm_01_create_vm(request, pre_init_db, + pre_create_host, + pre_create_tenant, + pre_create_net, + pre_create_image, + pre_create_flavor, + post_delete_image, + post_delete_flavor, + post_delete_vm, + post_delete_net, + post_delete_host): + """ + Create a vm and check network connection btw qrouter namespace and vm, evaluate using ping againt the ip given by + ovs dhcp server. Openvim is launched as a service by pre_launch_openvim_service before regresion start, is stopped + by post_stop_openvim_service after test regresion ends. + + :param request: Users argument --config= + :param pre_init_db: initialize the openvim db + :param pre_create_host: Create hosts + :param pre_create_tenant: Create tenant + :param pre_create_net: Create a mgmt net + :param pre_create_image: Create an image + :param pre_create_flavor: Create a flavor + :param post_delete_image: Delete the image declare by the test + :param post_delete_flavor: Delete the flavor declare by the test + :param post_delete_vm: Delete the vm declare by the test + :param post_delete_net: Delete the mgmt net declare by the test + :param post_delete_host: remove the host attached by the test + :return: + """ + config_path = request.config.getoption('config') + config = get_config(config_path) + if not config['fake_mode']: + vm_id = create_vm_per_host(config, 1) + assert vm_id + # get vlan id + vlan_id = os.environ['OPENVIM_TEST_MGMT_NET_VLAN'] + assert vlan_id + # get vm ip + ip = get_vm_ip(vm_id) + assert ip + # check ping against the vm + result = ping_ok(vlan_id, ip) + assert result + + +@pytest.mark.usefixtures('pre_init_db', 'pre_create_host', 'pre_create_tenant', 'pre_create_net', 'pre_create_image', + 'pre_create_flavor', 'post_delete_net','post_delete_host') +def test_osm_02_create_2_vm_ping_btw(request, pre_init_db, + pre_create_host, + pre_create_tenant, + pre_create_net, + pre_create_image, + pre_create_flavor, + post_delete_flavor, + post_delete_image, + post_delete_vm, + post_delete_net, + post_delete_host): + """ + Create 2 vms and check network connection btw qrouter namespace and vms, after ssh ready check ping btw both vms + to validate the vlxan mesh btw computes is ok. The vms ips are handle by ovs dhcp server. Openvim is launched as a + service by pre_launch_openvim_service before regresion start, is stopped by post_stop_openvim_service after + test regresion ends. + + :param request: Users argument --config= + :param pre_init_db: initialize the openvim db + :param pre_create_host: Create hosts + :param pre_create_tenant: Create tenant + :param pre_create_net: Create a mgmt net + :param pre_create_image: Create an image + :param pre_create_flavor: Create a flavor + :param post_delete_image: Delete the image declare by the test + :param post_delete_flavor: Delete the flavor declare by the test + :param post_delete_vm: Delete the vm declare by the test + :param post_delete_net: Delete the mgmt net declare by the test + :param post_delete_host: remove the host attached by the test + :return: + """ + config_path = request.config.getoption('config') + config = get_config(config_path) + + if not config['fake_mode']: + vm_id_1 = create_vm_per_host(config, 0) + assert vm_id_1 + + vm_id_2 = create_vm_per_host(config, 1) + assert vm_id_2 + + # get vlan id + vlan_id = os.environ['OPENVIM_TEST_MGMT_NET_VLAN'] + assert vlan_id + + # get vm ip + ip_1 = get_vm_ip(vm_id_1) + ip_2 = get_vm_ip(vm_id_2) + assert ip_2 + + # check ping against the vms + result = ping_ok(vlan_id, ip_1) + assert result + result = ping_ok(vlan_id, ip_2) + assert result + + # Wait for ssh to be ready + print "Wait for ssh to be ready" + time.sleep(90) + result = ping_ok_btw_2_vms(vlan_id, ip_1, ip_2) + assert result + + +@pytest.mark.usefixtures('pre_init_db', 'pre_create_host', 'pre_create_tenant', 'pre_create_net', 'pre_create_image', + 'pre_create_flavor', 'post_delete_net','post_delete_host') +def test_osm_03_test_service_openvim(request, pre_init_db, + pre_create_host, + pre_create_tenant, + pre_create_net, + pre_create_image, + pre_create_flavor, + post_delete_flavor, + post_delete_image, + post_delete_net, + post_delete_host): + """ + Create a net, restart openvim service and check net status to avoid issues with preexisting nets during openvim + startup. Openvim is launched as a service by pre_launch_openvim_service before regresion start, is stopped by + post_stop_openvim_service after test regresion ends. + + :param request: Users argument --config= + :param pre_init_db: initialize the openvim db + :param pre_create_host: Create hosts + :param pre_create_tenant: Create tenant + :param pre_create_net: Create a mgmt net + :param pre_create_image: Create an image + :param pre_create_flavor: Create a flavor + :param post_delete_image: Delete the image declare by the test + :param post_delete_flavor: Delete the flavor declare by the test + :param post_delete_net: Delete the mgmt net declare by the test + :param post_delete_host: remove the host attached by the test + :return: + """ + + net_id = os.environ['OPENVIM_TEST_MGMT_NET'] + status = get_net_status(net_id) + if 'ACTIVE' in status: + service_path = os.path.join(os.environ['OPENVIM_ROOT_FOLDER'], 'scripts', 'service-openvim') + execute_local('{} restart'.format(service_path)) + else: + # force test fail if net status is not ACTIVE + assert None + + status = get_net_status(net_id) + if 'ACTIVE' not in status: + assert None + + +def create_vm_per_host(config, host_number=0): + """ + Create a vm in an specific compute. + :param config: test config + :param host_number: compute number to be depolyed. + :return: + """ + # get env var for server descriptor + tenant_id = os.environ['OPENVIM_TENANT'] + image_id = os.environ['OPENVIM_TEST_IMAGE'] + flavor_id = os.environ['OPENVIM_TEST_FLAVOR'] + net_id = os.environ['OPENVIM_TEST_MGMT_NET'] + + values = {'OPENVIM_TENANT': tenant_id, + 'OPENVIM_TEST_IMAGE': image_id, + 'OPENVIM_TEST_FLAVOR': flavor_id, + 'OPENVIM_TEST_MGMT_NET': net_id, + 'HOST_ID': os.environ['OPENVIM_TEST_HOST_' + str(host_number)] + } + + descriptor = template_substitute(config['server'], values) + save_tmp_yaml('tmp.yaml', descriptor) + # create vm + openvim_path = os.path.join(os.environ['OPENVIM_ROOT_FOLDER'], 'openvim') + vm_id = execute_local("{} vm-create {}".format(openvim_path, 'tmp.yaml')) + vm_id = parse_uuid(vm_id) + delete_tmp_yaml('tmp.yaml') + return vm_id diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..025f4a0 --- /dev/null +++ b/tox.ini @@ -0,0 +1,22 @@ +[tox] +#envlist = py27,py3 +envlist = py27 +toxworkdir={homedir}/.tox + +[testenv] +deps=nose + mock +commands=nosetests + +[testenv:flake8] +basepython = python +deps = flake8 +commands = + flake8 setup.py + +[testenv:build] +basepython = python +deps = stdeb + setuptools-version-command +commands = python setup.py --command-packages=stdeb.command bdist_deb +