# contact with: nfvlabs@tid.es
##
-'''
-openmano python client used to interact with openmano-server
-'''
-__author__="Alfonso Tierno, Pablo Montes"
-__date__ ="$09-Mar-2016 09:09:48$"
-__version__="0.0.2-r468"
-version_date="Feb 2017"
+"""
+openmano python client used to interact with openmano-server
+"""
import requests
import json
import yaml
import logging
import sys
-if sys.version_info.major == 3:
+
+__author__ = "Alfonso Tierno, Pablo Montes"
+__date__ = "$09-Mar-2016 09:09:48$"
+__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
self.datacenter = self._get_item_uuid("datacenters", self.datacenter_id, self.datacenter_name, False)
return self.datacenter
- def _create_item(self, item, descriptor, all_tenants=False):
+ def _create_item(self, item, descriptor, all_tenants=False, api_version=None):
if all_tenants:
tenant_text = "/any"
- elif all_tenants==None:
+ elif all_tenants is None:
tenant_text = ""
else:
tenant_text = "/"+self._get_tenant()
payload_req = yaml.safe_dump(descriptor)
+
+ api_version_text = ""
+ if api_version:
+ api_version_text = "/v3"
#print payload_req
- URLrequest = "{}{}/{}".format(self.endpoint_url, tenant_text, item)
+ URLrequest = "{}{apiver}{tenant}/{item}".format(self.endpoint_url, apiver=api_version_text, tenant=tenant_text,
+ item=item)
self.logger.debug("openmano POST %s %s", URLrequest, payload_req)
- mano_response = requests.post(URLrequest, headers = self.headers_req, data=payload_req)
- self.logger.debug("openmano response: %s", mano_response.text )
+ mano_response = requests.post(URLrequest, headers=self.headers_req, data=payload_req)
+ self.logger.debug("openmano response: %s", mano_response.text)
content = self._parse_yaml(mano_response.text, response=True)
- if mano_response.status_code==200:
+ if mano_response.status_code == 200:
return content
else:
raise OpenmanoResponseException(str(content))
must be a dictionary or a json/yaml text.
must be a dictionary or a json/yaml text.
Other parameters can be:
+ #TODO, revise
name: the vnf name. Overwrite descriptor name if any
image_path: Can be a string or a string list. Overwrite the image_path at descriptor
description: vnf descriptor.. Overwrite descriptor description if any
pass
else:
raise OpenmanoBadParamsException("Missing descriptor")
-
- if 'vnf' not in descriptor or len(descriptor)>2:
- raise OpenmanoBadParamsException("Descriptor must contain only one 'vnf' field, and an optional version")
- for param in kwargs:
- if param == 'image_path':
- #print args.name
- try:
- if isinstance(kwargs[param], str):
- descriptor['vnf']['VNFC'][0]['VNFC image']=kwargs[param]
- elif isinstance(kwargs[param], tuple) or isinstance(kwargs[param], list):
- index=0
- for image_path_ in kwargs[param]:
- #print "image-path", image_path_
- descriptor['vnf']['VNFC'][index]['VNFC image']=image_path_
- index=index+1
- else:
- raise OpenmanoBadParamsException("Wrong image_path type. Expected text or a text list")
- except (KeyError, TypeError) as e:
- if str(e)=='vnf': error_pos= "missing field 'vnf'"
- elif str(e)=='VNFC': error_pos= "missing field 'vnf':'VNFC'"
- elif str(e)==str(index): error_pos= "field 'vnf':'VNFC' must be an array"
- elif str(e)=='VNFC image': error_pos= "missing field 'vnf':'VNFC'['VNFC image']"
- else: error_pos="wrong format"
- raise OpenmanoBadParamsException("Wrong VNF descriptor: " + error_pos)
+
+ try:
+ if "vnfd:vnfd-catalog" in descriptor or "vnfd-catalog" in descriptor:
+ api_version = "v3"
+ token = "vnfd"
+ vnfd_catalog = descriptor.get("vnfd:vnfd-catalog")
+ if not vnfd_catalog:
+ vnfd_catalog = descriptor.get("vnfd-catalog")
+ vnfds = vnfd_catalog.get("vnfd:vnfd")
+ if not vnfds:
+ vnfds = vnfd_catalog.get("vnfd")
+ vnfd = vnfds[0]
+ vdu_list = vnfd["vdu"]
+ elif "vnf" in descriptor: # old API
+ api_version = None
+ token = "vnfs"
+ vnfd = descriptor['vnf']
+ vdu_list = vnfd["VNFC"]
else:
- descriptor['vnf'][param] = kwargs[param]
- return self._create_item("vnfs", descriptor)
+ raise OpenmanoBadParamsException("Invalid VNF Descriptor must contain only one 'vnf' field or vnd-catalog")
+ except (KeyError, TypeError) as e:
+ raise OpenmanoBadParamsException("Invalid VNF Descriptor. Missing field {}".format(e))
+
+ if kwargs:
+ try:
+ if kwargs.get('name'):
+ vnfd['name'] = kwargs['name']
+ if kwargs.get('description'):
+ vnfd['description'] = kwargs['description']
+ if kwargs.get('image_path'):
+ error_param = 'image_path'
+ image_list = kwargs['image_path'].split(",")
+ image_item = image_list.pop(0)
+ # print "image-path", image_path_
+ for vdu in vdu_list:
+ if api_version == "v3":
+ if vdu.get("image"):
+ if image_item:
+ vdu['image'] = image_item
+ if "image-checksum" in vdu:
+ del vdu["image-checksum"]
+ if image_list:
+ image_item = image_list.pop(0)
+ for vol in vdu.get("volumes", ()): # image name in volumes
+ if image_item:
+ vol["image"] = image_item
+ if "image-checksum" in vol:
+ del vol["image-checksum"]
+ if image_list:
+ image_item = image_list.pop(0)
+ else:
+ if image_item:
+ vdu['VNFC image'] = image_item
+ if "image name" in vdu:
+ del vdu["image name"]
+ if "image checksum" in vdu:
+ del vdu["image checksum"]
+ if image_list:
+ image_item = image_list.pop(0)
+ for vol in vdu.get('devices', ()):
+ if vol['type'] != 'disk':
+ continue
+ if image_item:
+ vol['image'] = image_item
+ if "image name" in vol:
+ del vol["image name"]
+ if "image checksum" in vol:
+ del vol["image checksum"]
+ if image_list:
+ image_item = image_list.pop(0)
+ if kwargs.get('image_name'): # image name precedes if both are supplied
+ error_param = 'image_name'
+ image_list = kwargs['image_name'].split(",")
+ image_item = image_list.pop(0)
+ for vdu in vdu_list:
+ if api_version == "v3":
+ if vdu.get("image"):
+ if image_item:
+ vdu['image'] = image_item
+ if "image-checksum" in vdu:
+ del vdu["image-checksum"]
+ if image_list:
+ image_item = image_list.pop(0)
+ for vol in vdu.get("volumes", ()): # image name in volumes
+ if image_item:
+ vol["image"] = image_item
+ if "image-checksum" in vol:
+ del vol["image-checksum"]
+ if image_list:
+ image_item = image_list.pop(0)
+ else:
+ if image_item:
+ vdu['image name'] = image_item
+ if "VNFC image" in vdu:
+ del vdu["VNFC image"]
+ if image_list:
+ image_item = image_list.pop(0)
+ for vol in vdu.get('devices', ()):
+ if vol['type'] != 'disk':
+ continue
+ if image_item:
+ vol['image name'] = image_item
+ if "image" in vol:
+ del vol["image"]
+ if "image checksum" in vol:
+ del vol["image checksum"]
+ if image_list:
+ image_item = image_list.pop(0)
+
+ if kwargs.get('image_checksum'):
+ error_param = 'image_checksum'
+ image_list = kwargs['image_checksum'].split(",")
+ image_item = image_list.pop(0)
+ for vdu in vdu_list:
+ if api_version == "v3":
+ if vdu.get("image"):
+ if image_item:
+ vdu['image-checksum'] = image_item
+ if image_list:
+ image_item = image_list.pop(0)
+ for vol in vdu.get("volumes", ()): # image name in volumes
+ if image_item:
+ vol["mage-checksum"] = image_item
+ if image_list:
+ image_item = image_list.pop(0)
+ else:
+ if image_item:
+ vdu['image checksum'] = image_item
+ if "VNFC image" in vdu:
+ del vdu["VNFC image"]
+ if image_list:
+ image_item = image_list.pop(0)
+ for vol in vdu.get('devices', ()):
+ if vol['type'] != 'disk':
+ continue
+ if image_item:
+ vol['image checksum'] = image_item
+ if "image" in vol:
+ del vol["image"]
+ if image_list:
+ image_item = image_list.pop(0)
+ except IndexError:
+ raise OpenmanoBadParamsException("{} contains more items than {} at descriptor".format(
+ error_param, "vnfd-catalog:vnfd:vdu" if api_version else "vnf:VNFC"))
+ except (KeyError, TypeError) as e:
+ raise OpenmanoBadParamsException("Invalid VNF Descriptor. Missing field {}".format(e))
+ return self._create_item(token, descriptor, api_version=api_version)
# def edit_vnf(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False, **kwargs):
# '''Edit the parameters of a vnf
return self._del_item("scenarios", uuid, name, all_tenants)
def create_scenario(self, descriptor=None, descriptor_format=None, **kwargs):
- '''Creates a scenario
+ """Creates a scenario
Params: must supply a descriptor
descriptor: with format {'scenario':{new_scenario_info}}
must be a dictionary or a json/yaml text.
tenant_id. Propietary tenant
Return: Raises an exception on error
Obtain a dictionary with format {'scenario':{new_scenario_info}}
- '''
+ """
if isinstance(descriptor, str):
descriptor = self.parse(descriptor, descriptor_format)
elif descriptor:
else:
raise OpenmanoBadParamsException("Missing descriptor")
- if 'scenario' not in descriptor or len(descriptor)>2:
- raise OpenmanoBadParamsException("Descriptor must contain only one 'scenario' field, and an optional version")
+ try:
+ if "nsd:nsd-catalog" in descriptor or "nsd-catalog" in descriptor:
+ api_version = "v3"
+ token = "nsd"
+ nsd_catalog = descriptor.get("nsd:nsd-catalog")
+ if not nsd_catalog:
+ nsd_catalog = descriptor.get("nsd-catalog")
+ nsds = nsd_catalog.get("nsd:nsd")
+ if not nsds:
+ nsds = nsd_catalog.get("nsd")
+ nsd = nsds[0]
+ elif "scenario" in descriptor: # old API
+ api_version = None
+ token = "scenarios"
+ nsd = descriptor['scenario']
+ else:
+ raise OpenmanoBadParamsException("Invalid NS Descriptor must contain only one 'scenario' field or nsd-catalog")
+ except (KeyError, TypeError) as e:
+ raise OpenmanoBadParamsException("Invalid NS Descriptor. Missing field {}".format(e))
+
for param in kwargs:
- descriptor['scenario'][param] = kwargs[param]
- return self._create_item("scenarios", descriptor)
+ nsd[param] = kwargs[param]
+ return self._create_item(token, descriptor, api_version=api_version)
def edit_scenario(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False, **kwargs):
'''Edit the parameters of a scenario
elif descriptor:
pass
elif name and ("scenario_name" in kwargs or "scenario_id" in kwargs):
- descriptor = {"instance":{"name": name}}
+ descriptor = {"instance": {"name": name}}
else:
raise OpenmanoBadParamsException("Missing descriptor")
#
##
-'''
+"""
Module for testing openmano functionality. It uses openmanoclient.py for invoking openmano
-'''
-__author__ = "Pablo Montes, Alfonso Tierno"
-__date__ = "$16-Feb-2017 17:08:16$"
-__version__ = "0.0.4"
-version_date = "Jun 2017"
+"""
import logging
import os
-from argparse import ArgumentParser
import argcomplete
import unittest
import string
import inspect
import random
-import traceback
+# import traceback
import glob
import yaml
import sys
import time
-from pyvcloud.vcloudair import VCA
import uuid
import json
+from pyvcloud.vcloudair import VCA
+from argparse import ArgumentParser
+
+__author__ = "Pablo Montes, Alfonso Tierno"
+__date__ = "$16-Feb-2017 17:08:16$"
+__version__ = "0.1.0"
+version_date = "Oct 2017"
+
+test_config = {} # used for global variables with the test configuration
-global test_config # used for global variables with the test configuration
-test_config = {}
class test_base(unittest.TestCase):
test_index = 1
logger.debug("{}".format(tenant))
assert ('deleted' in tenant.get('result', ""))
+
class test_vimconn_connect(test_base):
def test_000_connect(self):
self.assertEqual((context.exception).http_code, 404)
+
'''
IMPORTANT NOTE
The following unittest class does not have the 'test_' on purpose. This test is the one used for the
class descriptor_based_scenario_test(test_base):
test_index = 0
scenario_test_path = None
- scenario_uuid = None
- instance_scenario_uuid = None
- to_delete_list = []
@classmethod
def setUpClass(cls):
cls.test_index = 1
cls.to_delete_list = []
+ cls.scenario_uuids = []
+ cls.instance_scenario_uuids = []
cls.scenario_test_path = test_config["test_directory"] + '/' + test_config["test_folder"]
logger.info("{}. {} {}".format(test_config["test_number"], cls.__name__, test_config["test_folder"]))
inspect.currentframe().f_code.co_name,
test_config["test_folder"])
self.__class__.test_index += 1
- vnfd_files = glob.glob(self.__class__.scenario_test_path+'/vnfd_*.yaml')
+ # load VNFD and NSD
+ descriptor_files = glob.glob(self.__class__.scenario_test_path+'/*.yaml')
+ vnf_descriptors = []
+ scenario_descriptors = []
+ for descriptor_file in descriptor_files:
+ with open(descriptor_file, 'r') as stream:
+ descriptor = yaml.load(stream)
+ if "vnf" in descriptor or "vnfd:vnfd-catalog" in descriptor or "vnfd-catalog" in descriptor:
+ vnf_descriptors.append(descriptor)
+ else:
+ scenario_descriptors.append(descriptor)
+
scenario_file = glob.glob(self.__class__.scenario_test_path + '/scenario_*.yaml')
- if len(vnfd_files) == 0 or len(scenario_file) > 1:
+ if not vnf_descriptors or not scenario_descriptors or len(scenario_descriptors) > 1:
raise Exception("Test '{}' not valid. It must contain an scenario file and at least one vnfd file'".format(
test_config["test_folder"]))
- #load all vnfd
- for vnfd in vnfd_files:
- with open(vnfd, 'r') as stream:
- vnf_descriptor = yaml.load(stream)
-
- vnfc_list = vnf_descriptor['vnf']['VNFC']
- for vnfc in vnfc_list:
- vnfc['image name'] = test_config["image_name"]
- devices = vnfc.get('devices',[])
- for device in devices:
- if device['type'] == 'disk' and 'image name' in device:
- device['image name'] = test_config["image_name"]
-
+ # load all vnfd
+ for vnf_descriptor in vnf_descriptors:
logger.debug("VNF descriptor: {}".format(vnf_descriptor))
- vnf = test_config["client"].create_vnf(descriptor=vnf_descriptor)
+ vnf = test_config["client"].create_vnf(descriptor=vnf_descriptor, image_name=test_config["image_name"])
logger.debug(vnf)
+ if 'vnf' in vnf:
+ vnf_uuid = vnf['vnf']['uuid']
+ else:
+ vnf_uuid = vnf['vnfd'][0]['uuid']
self.__class__.to_delete_list.insert(0, {"item": "vnf", "function": test_config["client"].delete_vnf,
- "params": {"uuid": vnf['vnf']['uuid']}})
-
- #load the scenario definition
- with open(scenario_file[0], 'r') as stream:
- scenario_descriptor = yaml.load(stream)
- networks = scenario_descriptor['scenario']['networks']
- networks[test_config["mgmt_net"]] = networks.pop('mgmt')
- logger.debug("Scenario descriptor: {}".format(scenario_descriptor))
- scenario = test_config["client"].create_scenario(descriptor=scenario_descriptor)
- logger.debug(scenario)
- self.__class__.to_delete_list.insert(0,{"item": "scenario", "function": test_config["client"].delete_scenario,
- "params":{"uuid": scenario['scenario']['uuid']} })
- self.__class__.scenario_uuid = scenario['scenario']['uuid']
+ "params": {"uuid": vnf_uuid}})
+
+ # load the scenario definition
+ for scenario_descriptor in scenario_descriptors:
+ # networks = scenario_descriptor['scenario']['networks']
+ # networks[test_config["mgmt_net"]] = networks.pop('mgmt')
+ logger.debug("Scenario descriptor: {}".format(scenario_descriptor))
+ scenario = test_config["client"].create_scenario(descriptor=scenario_descriptor)
+ logger.debug(scenario)
+ if 'scenario' in scenario:
+ scenario_uuid = scenario['scenario']['uuid']
+ else:
+ scenario_uuid = scenario['nsd'][0]['uuid']
+ self.__class__.to_delete_list.insert(0, {"item": "scenario",
+ "function": test_config["client"].delete_scenario,
+ "params": {"uuid": scenario_uuid}})
+ self.__class__.scenario_uuids.append(scenario_uuid)
def test_010_instantiate_scenario(self):
self.__class__.test_text = "{}.{}. TEST {} {}".format(test_config["test_number"], self.__class__.test_index,
inspect.currentframe().f_code.co_name,
test_config["test_folder"])
self.__class__.test_index += 1
-
- instance = test_config["client"].create_instance(scenario_id=self.__class__.scenario_uuid,
- name=self.__class__.test_text)
- self.__class__.instance_scenario_uuid = instance['uuid']
- logger.debug(instance)
- self.__class__.to_delete_list.insert(0, {"item": "instance", "function": test_config["client"].delete_instance,
- "params": {"uuid": instance['uuid']}})
+ for scenario_uuid in self.__class__.scenario_uuids:
+ instance_descriptor = {
+ "instance":{
+ "name": self.__class__.test_text,
+ "scenario": scenario_uuid,
+ "networks":{
+ "mgmt": {"sites": [ { "netmap-use": test_config["mgmt_net"]} ]}
+ }
+ }
+ }
+ instance = test_config["client"].create_instance(instance_descriptor)
+ self.__class__.instance_scenario_uuids.append(instance['uuid'])
+ logger.debug(instance)
+ self.__class__.to_delete_list.insert(0, {"item": "instance",
+ "function": test_config["client"].delete_instance,
+ "params": {"uuid": instance['uuid']}})
def test_020_check_deployent(self):
self.__class__.test_text = "{}.{}. TEST {} {}".format(test_config["test_number"], self.__class__.test_index,
return
keep_waiting = test_config["timeout"]
- instance_active = False
- while True:
- result = check_instance_scenario_active(self.__class__.instance_scenario_uuid)
- if result[0]:
- break
- elif 'ERROR' in result[1]:
- msg = 'Got error while waiting for the instance to get active: '+result[1]
- logging.error(msg)
- raise Exception(msg)
+ pending_instance_scenario_uuids = list(self.__class__.instance_scenario_uuids) # make a copy
+ while pending_instance_scenario_uuids:
+ index = 0
+ while index < len(pending_instance_scenario_uuids):
+ result = check_instance_scenario_active(pending_instance_scenario_uuids[index])
+ if result[0]:
+ del pending_instance_scenario_uuids[index]
+ break
+ elif 'ERROR' in result[1]:
+ msg = 'Got error while waiting for the instance to get active: '+result[1]
+ logging.error(msg)
+ raise Exception(msg)
+ index += 1
if keep_waiting >= 5:
time.sleep(5)