diff options
-rw-r--r-- | docker/Dockerfile | 3 | ||||
-rw-r--r-- | docker/Dockerfile.aarch64 | 3 | ||||
-rwxr-xr-x | functest/ci/config_functest.yaml | 1 | ||||
-rwxr-xr-x | functest/ci/testcases.yaml | 8 | ||||
-rw-r--r-- | functest/core/vnf_base.py | 26 | ||||
-rw-r--r-- | functest/opnfv_tests/vnf/ims/clearwater_ims_base.py | 149 | ||||
-rw-r--r-- | functest/opnfv_tests/vnf/ims/cloudify_ims.py | 142 | ||||
-rw-r--r--[-rwxr-xr-x] | functest/opnfv_tests/vnf/ims/opera_ims.py | 457 | ||||
-rw-r--r-- | functest/tests/unit/opnfv_tests/vnf/ims/test_cloudify_ims.py | 118 | ||||
-rw-r--r-- | functest/tests/unit/opnfv_tests/vnf/ims/test_ims_base.by | 58 |
10 files changed, 391 insertions, 574 deletions
diff --git a/docker/Dockerfile b/docker/Dockerfile index 4c0995b97..a2033a49a 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -92,6 +92,7 @@ RUN git clone --depth 1 -b $BRANCH https://gerrit.opnfv.org/gerrit/sfc ${REPOS_D RUN git clone --depth 1 -b $BRANCH https://gerrit.opnfv.org/gerrit/snaps ${REPOS_DIR}/snaps RUN git clone --depth 1 https://gerrit.opnfv.org/gerrit/securityscanning ${REPOS_DIR}/securityscanning RUN git clone --depth 1 https://gerrit.opnfv.org/gerrit/releng ${REPOS_DIR}/releng +RUN git clone --depth 1 https://gerrit.opnfv.org/gerrit/opera ${REPOS_DIR}/opera # OpenStack repositories RUN git clone --depth 1 -b $OPENSTACK_TAG https://github.com/openstack/networking-bgpvpn ${REPOS_DIR}/bgpvpn @@ -119,6 +120,8 @@ RUN cd ${RELENG_MODULE_DIR} \ RUN cd ${REPOS_DIR}/barometer \ && pip install . +RUN pip install ${REPOS_DIR}/opera + RUN find ${FUNCTEST_REPO_DIR} -name "*.py" \ -not -path "*tests/unit*" \ -not -path "*functest_venv*" \ diff --git a/docker/Dockerfile.aarch64 b/docker/Dockerfile.aarch64 index 17bf00027..83df2d0cb 100644 --- a/docker/Dockerfile.aarch64 +++ b/docker/Dockerfile.aarch64 @@ -88,6 +88,7 @@ RUN git clone --depth 1 -b $BRANCH https://gerrit.opnfv.org/gerrit/sfc ${REPOS_D RUN git clone --depth 1 -b $BRANCH https://gerrit.opnfv.org/gerrit/snaps ${REPOS_DIR}/snaps RUN git clone --depth 1 https://gerrit.opnfv.org/gerrit/securityscanning ${REPOS_DIR}/securityscanning RUN git clone --depth 1 https://gerrit.opnfv.org/gerrit/releng ${REPOS_DIR}/releng +RUN git clone --depth 1 https://gerrit.opnfv.org/gerrit/opera ${REPOS_DIR}/opera # OpenStack repositories RUN git clone --depth 1 -b $OPENSTACK_TAG https://github.com/openstack/networking-bgpvpn ${REPOS_DIR}/bgpvpn @@ -138,6 +139,8 @@ RUN curl -L https://get.rvm.io | bash -s stable # SNAPS integration RUN pip install -e ${REPOS_DIR}/snaps/ +RUN pip install ${REPOS_DIR}/opera + # SFC integration RUN /bin/bash -c ". ${REPOS_DIR}/sfc/sfc/tests/functest/setup_scripts/tacker_client_install.sh" RUN cd ${REPOS_DIR}/sfc && pip install -e . diff --git a/functest/ci/config_functest.yaml b/functest/ci/config_functest.yaml index 78f6257c8..95a4408a1 100755 --- a/functest/ci/config_functest.yaml +++ b/functest/ci/config_functest.yaml @@ -27,6 +27,7 @@ general: repo_parser: /home/opnfv/repos/parser repo_domino: /home/opnfv/repos/domino repo_snaps: /home/opnfv/repos/snaps + repo_opera: /home/opnfv/repos/opera repo_fds: /home/opnfv/repos/fds repo_securityscan: /home/opnfv/repos/securityscanning repo_vrouter: /home/opnfv/repos/vnfs/vrouter diff --git a/functest/ci/testcases.yaml b/functest/ci/testcases.yaml index 9a62770e9..1c33b9962 100755 --- a/functest/ci/testcases.yaml +++ b/functest/ci/testcases.yaml @@ -487,7 +487,7 @@ tiers: scenario: '(ocl)|(nosdn)|^(os-odl)((?!bgpvpn).)*$' run: module: 'functest.opnfv_tests.vnf.ims.cloudify_ims' - class: 'ImsVnf' + class: 'CloudifyIms' # - # name: aaa # criteria: 'ret == 0' @@ -517,17 +517,17 @@ tiers: - name: opera_ims - criteria: 'ret == 0' + criteria: 'status == "PASS"' blocking: false clean_flag: true description: >- - Evolution of vIMS + VNF deployment with OPEN-O dependencies: installer: 'unknown' scenario: 'unknown' run: module: 'functest.opnfv_tests.vnf.ims.opera_ims' - class: 'ImsVnf' + class: 'OperaIms' - name: vyos_vrouter diff --git a/functest/core/vnf_base.py b/functest/core/vnf_base.py index c374c4917..3f0adcc66 100644 --- a/functest/core/vnf_base.py +++ b/functest/core/vnf_base.py @@ -7,15 +7,14 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 -import time - import inspect +import time +import functest.core.testcase as base +from functest.utils.constants import CONST import functest.utils.functest_logger as ft_logger -import functest.utils.openstack_utils as os_utils import functest.utils.functest_utils as ft_utils -import testcase as base -from functest.utils.constants import CONST +import functest.utils.openstack_utils as os_utils class VnfOnBoardingBase(base.TestCase): @@ -29,7 +28,7 @@ class VnfOnBoardingBase(base.TestCase): self.case_name = case self.cmd = cmd self.details = {} - self.data_dir = CONST.dir_functest_data + self.result_dir = CONST.dir_results self.details['orchestrator'] = {} self.details['vnf'] = {} self.details['test_vnf'] = {} @@ -39,14 +38,14 @@ class VnfOnBoardingBase(base.TestCase): 'vnf_{}_tenant_name'.format(self.case_name)) self.tenant_description = CONST.__getattribute__( 'vnf_{}_tenant_description'.format(self.case_name)) - except: + except Exception: # raise Exception("Unknown VNF case=" + self.case_name) self.logger.error("Unknown VNF case={}".format(self.case_name)) try: self.images = CONST.__getattribute__( 'vnf_{}_tenant_images'.format(self.case_name)) - except: + except Exception: self.logger.warn("No tenant image defined for this VNF") def execute(self): @@ -234,7 +233,12 @@ class VnfOnBoardingBase(base.TestCase): def step_failure(self, error_msg): part = inspect.stack()[1][3] - self.details[part]['status'] = 'FAIL' - self.details[part]['result'] = error_msg - self.logger.error("Step failure:{}".format(error_msg)) + self.logger.error("Step '%s' failed: %s", part, error_msg) + try: + part_info = self.details[part] + except KeyError: + self.details[part] = {} + part_info = self.details[part] + part_info['status'] = 'FAIL' + part_info['result'] = error_msg raise Exception(error_msg) diff --git a/functest/opnfv_tests/vnf/ims/clearwater_ims_base.py b/functest/opnfv_tests/vnf/ims/clearwater_ims_base.py new file mode 100644 index 000000000..f21ce3f9a --- /dev/null +++ b/functest/opnfv_tests/vnf/ims/clearwater_ims_base.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python +# +# Copyright (c) 2017 All rights reserved +# This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# +# http://www.apache.org/licenses/LICENSE-2.0 +import json +import os +import shutil + +import requests + +import functest.core.vnf_base as vnf_base +from functest.utils.constants import CONST +import functest.utils.functest_logger as ft_logger +import functest.utils.functest_utils as ft_utils + + +class ClearwaterOnBoardingBase(vnf_base.VnfOnBoardingBase): + + def __init__(self, project='functest', case='', repo='', cmd=''): + self.logger = ft_logger.Logger(__name__).getLogger() + super(ClearwaterOnBoardingBase, self).__init__( + project, case, repo, cmd) + self.case_dir = os.path.join(CONST.dir_functest_test, 'vnf', 'ims') + self.data_dir = CONST.dir_ims_data + self.result_dir = os.path.join(CONST.dir_results, case) + self.test_dir = CONST.dir_repo_vims_test + + if not os.path.exists(self.data_dir): + os.makedirs(self.data_dir) + if not os.path.exists(self.result_dir): + os.makedirs(self.result_dir) + + def config_ellis(self, ellis_ip, signup_code='secret', two_numbers=False): + output_dict = {} + self.logger.info('Configure Ellis: %s', ellis_ip) + output_dict['ellis_ip'] = ellis_ip + account_url = 'http://{0}/accounts'.format(ellis_ip) + params = {"password": "functest", + "full_name": "opnfv functest user", + "email": "functest@opnfv.org", + "signup_code": signup_code} + rq = requests.post(account_url, data=params) + output_dict['login'] = params + if rq.status_code != 201 and rq.status_code != 409: + raise Exception("Unable to create an account for number" + " provision: %s" % rq.json()['reason']) + self.logger.info('Account is created on Ellis: %s', params) + + session_url = 'http://{0}/session'.format(ellis_ip) + session_data = { + 'username': params['email'], + 'password': params['password'], + 'email': params['email'] + } + rq = requests.post(session_url, data=session_data) + if rq.status_code != 201: + raise Exception('Failed to get cookie for Ellis') + cookies = rq.cookies + self.logger.info('Cookies: %s' % cookies) + + number_url = 'http://{0}/accounts/{1}/numbers'.format( + ellis_ip, + params['email']) + self.logger.info('Create 1st calling number on Ellis') + number_res = self.create_ellis_number(number_url, cookies) + output_dict['number'] = number_res + + if two_numbers: + self.logger.info('Create 2nd calling number on Ellis') + number_res = self.create_ellis_number(number_url, cookies) + output_dict['number2'] = number_res + + return output_dict + + def create_ellis_number(self, number_url, cookies): + rq = requests.post(number_url, cookies=cookies) + + if rq.status_code != 200: + if rq and rq.json(): + reason = rq.json()['reason'] + else: + reason = rq + raise Exception("Unable to create a number: %s" % reason) + number_res = rq.json() + self.logger.info('Calling number is created: %s', number_res) + return number_res + + def run_clearwater_live_test(self, dns_ip, public_domain, + bono_ip=None, ellis_ip=None, + signup_code='secret'): + self.logger.info('Run Clearwater live test') + nameservers = ft_utils.get_resolvconf_ns() + resolvconf = ['{0}{1}{2}'.format(os.linesep, 'nameserver ', ns) + for ns in nameservers] + self.logger.debug('resolvconf: %s', resolvconf) + dns_file = '/etc/resolv.conf' + dns_file_bak = '/etc/resolv.conf.bak' + shutil.copy(dns_file, dns_file_bak) + script = ('echo -e "nameserver {0}{1}" > {2};' + 'source /etc/profile.d/rvm.sh;' + 'cd {3};' + 'rake test[{4}] SIGNUP_CODE={5}' + .format(dns_ip, + ''.join(resolvconf), + dns_file, + self.test_dir, + public_domain, + signup_code)) + if bono_ip and ellis_ip: + subscript = ' PROXY={0} ELLIS={1}'.format(bono_ip, ellis_ip) + script = '{0}{1}'.format(script, subscript) + script = ('{0}{1}'.format(script, ' --trace')) + cmd = "/bin/bash -c '{0}'".format(script) + self.logger.info('Live test cmd: %s', cmd) + output_file = os.path.join(self.result_dir, "ims_test_output.txt") + ft_utils.execute_command(cmd, + error_msg='Clearwater live test failed', + output_file=output_file) + + with open(dns_file_bak, 'r') as bak_file: + result = bak_file.read() + with open(dns_file, 'w') as f: + f.write(result) + + f = open(output_file, 'r') + result = f.read() + if result != "": + self.logger.debug(result) + + vims_test_result = "" + tempFile = os.path.join(self.test_dir, "temp.json") + try: + self.logger.debug("Trying to load test results") + with open(tempFile) as f: + vims_test_result = json.load(f) + f.close() + except Exception: + self.logger.error("Unable to retrieve test results") + + try: + os.remove(tempFile) + except Exception: + self.logger.error("Deleting file failed") + + return vims_test_result diff --git a/functest/opnfv_tests/vnf/ims/cloudify_ims.py b/functest/opnfv_tests/vnf/ims/cloudify_ims.py index f7dfd532f..404f208eb 100644 --- a/functest/opnfv_tests/vnf/ims/cloudify_ims.py +++ b/functest/opnfv_tests/vnf/ims/cloudify_ims.py @@ -7,42 +7,37 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 -import json import os -import requests -import subprocess import sys import time + +import requests import yaml -import functest.core.vnf_base as vnf_base +from functest.opnfv_tests.vnf.ims.clearwater import Clearwater +import functest.opnfv_tests.vnf.ims.clearwater_ims_base as clearwater_ims_base +from functest.opnfv_tests.vnf.ims.orchestrator_cloudify import Orchestrator +from functest.utils.constants import CONST import functest.utils.functest_logger as ft_logger import functest.utils.functest_utils as ft_utils import functest.utils.openstack_utils as os_utils -from clearwater import Clearwater -from functest.utils.constants import CONST -from orchestrator_cloudify import Orchestrator - -class ImsVnf(vnf_base.VnfOnBoardingBase): +class CloudifyIms(clearwater_ims_base.ClearwaterOnBoardingBase): def __init__(self, project='functest', case='cloudify_ims', repo='', cmd=''): - super(ImsVnf, self).__init__(project, case, repo, cmd) - self.logger = ft_logger.Logger("vIMS").getLogger() - self.case_dir = os.path.join(CONST.dir_functest_test, 'vnf/ims/') - self.data_dir = CONST.dir_ims_data - self.test_dir = CONST.dir_repo_vims_test + super(CloudifyIms, self).__init__(project, case, repo, cmd) + self.logger = ft_logger.Logger(__name__).getLogger() # Retrieve the configuration try: self.config = CONST.__getattribute__( 'vnf_{}_config'.format(self.case_name)) - except: + except Exception: raise Exception("VNF config file not found") - config_file = self.case_dir + self.config + config_file = os.path.join(self.case_dir, self.config) self.orchestrator = dict( requirements=get_config("cloudify.requirements", config_file), blueprint=get_config("cloudify.blueprint", config_file), @@ -61,10 +56,6 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): self.images = get_config("tenant_images", config_file) self.logger.info("Images needed for vIMS: %s" % self.images) - # vIMS Data directory creation - if not os.path.exists(self.data_dir): - os.makedirs(self.data_dir) - def deploy_orchestrator(self, **kwargs): self.logger.info("Additional pre-configuration steps") @@ -82,7 +73,7 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): image_id = os_utils.get_image_id(self.glance_client, image_name) self.logger.debug("image_id: %s" % image_id) - except: + except Exception: self.logger.error("Unexpected error: %s" % sys.exc_info()[0]) if image_id == '': @@ -177,10 +168,11 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): self.logger.debug("Resolvconf set") self.logger.info("Prepare virtualenv for cloudify-cli") - cmd = "chmod +x " + self.case_dir + "create_venv.sh" + venv_scrit_dir = os.path.join(self.case_dir, "create_venv.sh") + cmd = "chmod +x " + venv_scrit_dir ft_utils.execute_command(cmd) time.sleep(3) - cmd = self.case_dir + "create_venv.sh " + self.data_dir + cmd = venv_scrit_dir + " " + self.data_dir ft_utils.execute_command(cmd) cfy.download_manager_blueprint( @@ -251,99 +243,25 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): self.logger.debug("Trying to get clearwater manager IP ... ") mgr_ip = os.popen(cmd).read() mgr_ip = mgr_ip.splitlines()[0] - except: + except Exception: self.step_failure("Unable to retrieve the IP of the " "cloudify manager server !") - api_url = "http://" + mgr_ip + "/api/v2" - dep_outputs = requests.get(api_url + "/deployments/" + - self.vnf['deployment_name'] + "/outputs") - dns_ip = dep_outputs.json()['outputs']['dns_ip'] - ellis_ip = dep_outputs.json()['outputs']['ellis_ip'] - - self.logger.debug("DNS ip : %s" % dns_ip) - self.logger.debug("ELLIS ip : %s" % ellis_ip) - - ellis_url = "http://" + ellis_ip + "/" - url = ellis_url + "accounts" - - params = {"password": "functest", - "full_name": "opnfv functest user", - "email": "functest@opnfv.fr", - "signup_code": "secret"} - - rq = requests.post(url, data=params) - i = 30 - while rq.status_code != 201 and i > 0: - rq = requests.post(url, data=params) - self.logger.debug("Account creation http status code: %s" - % rq.status_code) - i = i - 1 - time.sleep(10) - - if rq.status_code == 201: - url = ellis_url + "session" - rq = requests.post(url, data=params) - cookies = rq.cookies - else: - self.step_failure("Unable to create an account") - - url = ellis_url + "accounts/" + params['email'] + "/numbers" - if cookies != "": - rq = requests.post(url, cookies=cookies) - i = 24 - while rq.status_code != 200 and i > 0: - rq = requests.post(url, cookies=cookies) - self.logger.debug("Number creation http status code: %s" - % rq.status_code) - i = i - 1 - time.sleep(25) - - if rq.status_code != 200: - self.step_failure("Unable to create a number: %s" - % rq.json()['reason']) - - nameservers = ft_utils.get_resolvconf_ns() - resolvconf = "" - for ns in nameservers: - resolvconf += "\nnameserver " + ns + self.logger.info('Cloudify Manager: %s', mgr_ip) + api_url = 'http://{0}/api/v2/deployments/{1}/outputs'.format( + mgr_ip, self.vnf['deployment_name']) + dep_outputs = requests.get(api_url) + self.logger.info(api_url) + outputs = dep_outputs.json()['outputs'] + self.logger.info("Deployment outputs: %s", outputs) + dns_ip = outputs['dns_ip'] + ellis_ip = outputs['ellis_ip'] + self.config_ellis(ellis_ip) if dns_ip != "": - script = ('echo -e "nameserver ' + dns_ip + resolvconf + - '" > /etc/resolv.conf; ') - script += 'source /etc/profile.d/rvm.sh; ' - script += 'cd {0}; ' - script += ('rake test[{1}] SIGNUP_CODE="secret"') - - cmd = ("/bin/bash -c '" + - script.format(self.data_dir, self.inputs["public_domain"]) + - "'") - output_file = "output.txt" - f = open(output_file, 'w+') - subprocess.call(cmd, shell=True, stdout=f, - stderr=subprocess.STDOUT) - f.close() - - f = open(output_file, 'r') - result = f.read() - if result != "": - self.logger.debug(result) - - vims_test_result = "" - tempFile = os.path.join(self.test_dir, "temp.json") - try: - self.logger.debug("Trying to load test results") - with open(tempFile) as f: - vims_test_result = json.load(f) - f.close() - except: - self.logger.error("Unable to retrieve test results") - - try: - os.remove(tempFile) - except: - self.logger.error("Deleting file failed") - + vims_test_result = self.run_clearwater_live_test( + dns_ip=dns_ip, + public_domain=self.inputs["public_domain"]) if vims_test_result != '': return {'status': 'PASS', 'result': vims_test_result} else: @@ -352,7 +270,7 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): def clean(self): self.vnf['object'].undeploy_vnf() self.orchestrator['object'].undeploy_manager() - super(ImsVnf, self).clean() + super(CloudifyIms, self).clean() def main(self, **kwargs): self.logger.info("Cloudify IMS VNF onboarding test starting") diff --git a/functest/opnfv_tests/vnf/ims/opera_ims.py b/functest/opnfv_tests/vnf/ims/opera_ims.py index 7ead401fe..d022b3c7f 100755..100644 --- a/functest/opnfv_tests/vnf/ims/opera_ims.py +++ b/functest/opnfv_tests/vnf/ims/opera_ims.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (c) 2016 Orange and others. +# Copyright (c) 2017 HUAWEI TECHNOLOGIES CO.,LTD and others. # # All rights reserved. This program and the accompanying materials # are made available under the terms of the Apache License, Version 2.0 @@ -8,381 +8,117 @@ # http://www.apache.org/licenses/LICENSE-2.0 import json -import socket -import sys +import os import time -import yaml -import functest.core.vnf_base as vnf_base -import functest.utils.functest_logger as ft_logger -import functest.utils.functest_utils as ft_utils -import functest.utils.openstack_utils as os_utils -import os +from opera import openo_connect +import requests + +import functest.opnfv_tests.vnf.ims.clearwater_ims_base as clearwater_ims_base from functest.utils.constants import CONST +import functest.utils.functest_logger as ft_logger -from org.openbaton.cli.agents.agents import MainAgent -from org.openbaton.cli.errors.errors import NfvoException +class OperaIms(clearwater_ims_base.ClearwaterOnBoardingBase): -def servertest(host, port): - args = socket.getaddrinfo(host, port, socket.AF_INET, socket.SOCK_STREAM) - for family, socktype, proto, canonname, sockaddr in args: - s = socket.socket(family, socktype, proto) + def __init__(self, project='functest', case='opera_ims', + repo=CONST.dir_repo_opera, cmd=''): + super(OperaIms, self).__init__(project, case, repo, cmd) + self.logger = ft_logger.Logger(__name__).getLogger() + self.ellis_file = os.path.join(self.result_dir, 'ellis.info') + self.live_test_file = os.path.join(self.result_dir, + 'live_test_report.json') try: - s.connect(sockaddr) - except socket.error: - return False + self.openo_msb_endpoint = os.environ['OPENO_MSB_ENDPOINT'] + except KeyError: + raise Exception('OPENO_MSB_ENDPOINT is not specified,' + ' put it as <OPEN-O ip>:<port>') else: - s.close() - return True - -# ---------------------------------------------------------- -# -# UTILS -# -# ----------------------------------------------------------- - - -def get_config(parameter, file): - """ - Returns the value of a given parameter in file.yaml - parameter must be given in string format with dots - Example: general.openstack.image_name - """ - with open(file) as f: - file_yaml = yaml.safe_load(f) - f.close() - value = file_yaml - for element in parameter.split("."): - value = value.get(element) - if value is None: - raise ValueError("The parameter %s is not defined in" - " reporting.yaml" % parameter) - return value - - -def download_and_add_image_on_glance(glance, image_name, - image_url, data_dir): - dest_path = data_dir - if not os.path.exists(dest_path): - os.makedirs(dest_path) - file_name = image_url.rsplit('/')[-1] - if not ft_utils.download_url(image_url, dest_path): - return False - image = os_utils.create_glance_image( - glance, image_name, dest_path + file_name) - if not image: - return False - return image - - -class ImsVnf(vnf_base.VnfOnBoardingBase): - - def __init__(self, project='functest', case='orchestra_ims', - repo='', cmd=''): - super(ImsVnf, self).__init__(project, case, repo, cmd) - self.ob_password = "openbaton" - self.ob_username = "admin" - self.ob_https = False - self.ob_port = "8080" - self.ob_ip = "localhost" - self.ob_instance_id = "" - self.logger = ft_logger.Logger("orchestra_ims").getLogger() - self.case_dir = os.path.join(CONST.dir_functest_test, 'vnf/ims/') - self.data_dir = CONST.dir_ims_data - self.test_dir = CONST.dir_repo_vims_test - self.ob_projectid = "" - self.keystone_client = os_utils.get_keystone_client() - self.ob_nsr_id = "" - self.main_agent = None - # vIMS Data directory creation - if not os.path.exists(self.data_dir): - os.makedirs(self.data_dir) - # Retrieve the configuration - try: - self.config = CONST.__getattribute__( - 'vnf_{}_config'.format(self.case_name)) - except: - raise Exception("Orchestra VNF config file not found") - config_file = self.case_dir + self.config - self.imagename = get_config("openbaton.imagename", config_file) - self.market_link = get_config("openbaton.marketplace_link", - config_file) - self.images = get_config("tenant_images", config_file) - - def deploy_orchestrator(self, **kwargs): - self.logger.info("Additional pre-configuration steps") - nova_client = os_utils.get_nova_client() - neutron_client = os_utils.get_neutron_client() - glance_client = os_utils.get_glance_client() - - # needs some images - self.logger.info("Upload some OS images if it doesn't exist") - temp_dir = os.path.join(self.data_dir, "tmp/") - for image_name, image_url in self.images.iteritems(): - self.logger.info("image: %s, url: %s" % (image_name, image_url)) - try: - image_id = os_utils.get_image_id(glance_client, - image_name) - self.logger.info("image_id: %s" % image_id) - except: - self.logger.error("Unexpected error: %s" % sys.exc_info()[0]) - - if image_id == '': - self.logger.info("""%s image doesn't exist on glance repository. Try - downloading this image and upload on glance !""" % image_name) - image_id = download_and_add_image_on_glance(glance_client, - image_name, - image_url, - temp_dir) - if image_id == '': - self.step_failure( - "Failed to find or upload required OS " - "image for this deployment") - network_dic = os_utils.create_network_full(neutron_client, - "openbaton_mgmt", - "openbaton_mgmt_subnet", - "openbaton_router", - "192.168.100.0/24") - - # orchestrator VM flavor - self.logger.info("Check medium Flavor is available, if not create one") - flavor_exist, flavor_id = os_utils.get_or_create_flavor( - "m1.medium", - "4096", - '1', - '2', - public=True) - self.logger.debug("Flavor id: %s" % flavor_id) - - if not network_dic: - self.logger.error("There has been a problem when creating the " - "neutron network") - - network_id = network_dic["net_id"] - - self.logger.info("Creating floating IP for VM in advance...") - floatip_dic = os_utils.create_floating_ip(neutron_client) - floatip = floatip_dic['fip_addr'] - - if floatip is None: - self.logger.error("Cannot create floating IP.") - - userdata = "#!/bin/bash\n" - userdata += "set -x\n" - userdata += "set -e\n" - userdata += "echo \"nameserver 8.8.8.8\" >> /etc/resolv.conf\n" - userdata += "apt-get install curl\n" - userdata += ("echo \"rabbitmq_broker_ip=%s\" > ./config_file\n" - % floatip) - userdata += "echo \"mysql=no\" >> ./config_file\n" - userdata += ("echo \"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCuPXrV3" - "geeHc6QUdyUr/1Z+yQiqLcOskiEGBiXr4z76MK4abiFmDZ18OMQlc" - "fl0p3kS0WynVgyaOHwZkgy/DIoIplONVr2CKBKHtPK+Qcme2PVnCtv" - "EqItl/FcD+1h5XSQGoa+A1TSGgCod/DPo+pes0piLVXP8Ph6QS1k7S" - "ic7JDeRQ4oT1bXYpJ2eWBDMfxIWKZqcZRiGPgMIbJ1iEkxbpeaAd9O" - "4MiM9nGCPESmed+p54uYFjwEDlAJZShcAZziiZYAvMZhvAhe6USljc" - "7YAdalAnyD/jwCHuwIrUw/lxo7UdNCmaUxeobEYyyFA1YVXzpNFZya" - "XPGAAYIJwEq/ openbaton@opnfv\" >> /home/ubuntu/.ssh/aut" - "horized_keys\n") - userdata += "cat ./config_file\n" - userdata += ("curl -s http://get.openbaton.org/bootstrap " - "> ./bootstrap\n") - userdata += "export OPENBATON_COMPONENT_AUTOSTART=false\n" - bootstrap = "sh ./bootstrap release -configFile=./config_file" - userdata += bootstrap + "\n" - - userdata += ("echo \"nfvo.plugin.timeout=300000\" >> " - "/etc/openbaton/openbaton-nfvo.properties\n") - userdata += "service openbaton-nfvo restart\n" - userdata += "service openbaton-vnfm-generic restart\n" - - sg_id = os_utils.create_security_group_full(neutron_client, - "orchestra-sec-group", - "allowall") - - os_utils.create_secgroup_rule(neutron_client, sg_id, "ingress", - "icmp", 0, 255) - os_utils.create_secgroup_rule(neutron_client, sg_id, "egress", - "icmp", 0, 255) - os_utils.create_secgroup_rule(neutron_client, sg_id, "ingress", - "tcp", 1, 65535) - os_utils.create_secgroup_rule(neutron_client, sg_id, "ingress", - "udp", 1, 65535) - os_utils.create_secgroup_rule(neutron_client, sg_id, "egress", - "tcp", 1, 65535) - os_utils.create_secgroup_rule(neutron_client, sg_id, "egress", - "udp", 1, 65535) - - self.logger.info("Security group set") - - self.logger.info("Create instance....") - self.logger.info("flavor: m1.medium\n" - "image: %s\n" - "network_id: %s\n" - "userdata: %s\n" - % (self.imagename, network_id, userdata)) - - instance = os_utils.create_instance_and_wait_for_active( - "m1.medium", - os_utils.get_image_id(glance_client, self.imagename), - network_id, - "orchestra-openbaton", - config_drive=False, - userdata=userdata) + self.logger.info('OPEN-O endpoint is: %s', self.openo_msb_endpoint) - self.ob_instance_id = instance.id + def prepare(self): + pass - self.logger.info("Adding sec group to orchestra instance") - os_utils.add_secgroup_to_instance(nova_client, - self.ob_instance_id, sg_id) - - self.logger.info("Associating floating ip: '%s' to VM '%s' " - % (floatip, "orchestra-openbaton")) - if not os_utils.add_floating_ip(nova_client, instance.id, floatip): - self.logger.error("Cannot associate floating IP to VM.") - self.step_failure("Cannot associate floating IP to VM.") - - self.logger.info("Waiting for nfvo to be up and running...") - x = 0 - while x < 100: - if servertest(floatip, "8080"): - break - else: - self.logger.debug("openbaton is not started yet") - time.sleep(5) - x += 1 - - if x == 100: - self.logger.error("Openbaton is not started correctly") - self.step_failure("Openbaton is not started correctly") - - self.ob_ip = floatip - self.ob_password = "openbaton" - self.ob_username = "admin" - self.ob_https = False - self.ob_port = "8080" - - self.logger.info("Deploy orchestrator: OK") + def clean(self): + pass def deploy_vnf(self): - self.logger.info("vIMS Deployment") - - self.main_agent = MainAgent(nfvo_ip=self.ob_ip, - nfvo_port=self.ob_port, - https=self.ob_https, - version=1, - username=self.ob_username, - password=self.ob_password) - - project_agent = self.main_agent.get_agent("project", self.ob_projectid) - for p in json.loads(project_agent.find()): - if p.get("name") == "default": - self.ob_projectid = p.get("id") - break - - self.logger.debug("project id: %s" % self.ob_projectid) - if self.ob_projectid == "": - self.logger.error("Default project id was not found!") - self.step_failure("Default project id was not found!") - - vim_json = { - "name": "vim-instance", - "authUrl": os_utils.get_credentials().get("auth_url"), - "tenant": os_utils.get_credentials().get("tenant_name"), - "username": os_utils.get_credentials().get("username"), - "password": os_utils.get_credentials().get("password"), - # "keyPair": "opnfv", - # TODO change the keypair to correct value - # or upload a correct one or remove it - "securityGroups": [ - "default", - "orchestra-sec-group" - ], - "type": "openstack", - "location": { - "name": "opnfv", - "latitude": "52.525876", - "longitude": "13.314400" - } - } - - self.logger.debug("vim: %s" % vim_json) - - self.main_agent.get_agent( - "vim", - project_id=self.ob_projectid).create(entity=json.dumps(vim_json)) - - market_agent = self.main_agent.get_agent("market", - project_id=self.ob_projectid) - - nsd = {} - try: - self.logger.info("sending: %s" % self.market_link) - nsd = market_agent.create(entity=self.market_link) - self.logger.info("Onboarded nsd: " + nsd.get("name")) - except NfvoException as e: - self.step_failure(e.message) - - nsr_agent = self.main_agent.get_agent("nsr", - project_id=self.ob_projectid) - nsd_id = nsd.get('id') - if nsd_id is None: - self.step_failure("NSD not onboarded correctly") - - nsr = None try: - nsr = nsr_agent.create(nsd_id) - except NfvoException as e: - self.step_failure(e.message) - - if nsr.get('code') is not None: - self.logger.error( - "vIMS cannot be deployed: %s -> %s" % - (nsr.get('code'), nsr.get('message'))) - self.step_failure("vIMS cannot be deployed") - - i = 0 - self.logger.info("waiting NSR to go to active...") - while nsr.get("status") != 'ACTIVE' and nsr.get("status") != 'ERROR': - i += 1 - if i == 100: - self.step_failure("After %s sec the nsr did not go to active.." - % 5 * 100) - time.sleep(5) - nsr = json.loads(nsr_agent.find(nsr.get('id'))) - - if nsr.get("status") == 'ACTIVE': - deploy_vnf = {'status': "PASS", 'result': nsr} - self.logger.info("Deploy VNF: OK") + openo_connect.create_service(self.openo_msb_endpoint, + 'functest_opera', + 'VNF for functest testing') + except Exception as e: + self.logger.error(e) + return {'status': 'FAIL', 'result': e} else: - deploy_vnf = {'status': "FAIL", 'result': nsr} - self.logger.error("Deploy VNF: ERROR") - self.step_failure("Deploy vIMS failed") - self.ob_nsr_id = nsr.get("id") - return deploy_vnf + self.logger.info('vIMS deployment is kicked off') + return {'status': 'PASS', 'result': ''} - def test_vnf(self): - # Adaptations probably needed - # code used for cloudify_ims - # ruby client on jumphost calling the vIMS on the SUT - return + def dump_info(self, info_file, result): + with open(info_file, 'w') as f: + self.logger.debug('Save information to file: %s', info_file) + json.dump(result, f) - def clean(self): - self.main_agent.get_agent( - "nsr", - project_id=self.ob_projectid).delete(self.ob_nsr_id) - time.sleep(5) - os_utils.delete_instance(nova_client=os_utils.get_nova_client(), - instance_id=self.ob_instance_id) - # TODO question is the clean removing also the VM? - # I think so since is goinf to remove the tenant... - super(ImsVnf, self).clean() + def test_vnf(self): + vnfm_ip = openo_connect.get_vnfm_ip(self.openo_msb_endpoint) + self.logger.info('VNFM IP: %s', vnfm_ip) + vnf_status_url = 'http://{0}:5000/api/v1/model/status'.format(vnfm_ip) + vnf_alive = False + retry = 15 + + self.logger.info('Check the VNF status') + while retry > 0: + rq = requests.get(vnf_status_url) + response = rq.json() + vnf_alive = response['vnf_alive'] + msg = response['msg'] + self.logger.info(msg) + if vnf_alive: + break + self.logger.info('check again in one minute...') + retry = retry - 1 + time.sleep(60) + + if not vnf_alive: + raise Exception('VNF failed to start: {0}'.format(msg)) + + ellis_config_url = ('http://{0}:5000/api/v1/model/ellis/configure' + .format(vnfm_ip)) + rq = requests.get(ellis_config_url, timeout=60) + if rq.json() and not rq.json()['ellis_ok']: + self.logger.error(rq.json()['data']) + raise Exception('Failed to configure Ellis') + + self.logger.info('Get Clearwater deployment detail') + vnf_info_url = ('http://{0}:5000/api/v1/model/output' + .format(vnfm_ip)) + rq = requests.get(vnf_info_url, timeout=60) + data = rq.json()['data'] + self.logger.info(data) + bono_ip = data['bono_ip'] + ellis_ip = data['ellis_ip'] + dns_ip = data['dns_ip'] + result = self.config_ellis(ellis_ip, 'signup', True) + self.logger.debug('Ellis Result: %s', result) + self.dump_info(self.ellis_file, result) + + if dns_ip: + vims_test_result = self.run_clearwater_live_test( + dns_ip, + 'clearwater.local', + bono_ip, + ellis_ip, + 'signup') + if vims_test_result != '': + self.dump_info(self.live_test_file, vims_test_result) + return {'status': 'PASS', 'result': vims_test_result} + else: + return {'status': 'FAIL', 'result': ''} def main(self, **kwargs): - self.logger.info("Orchestra IMS VNF onboarding test starting") + self.logger.info("Start to run Opera vIMS VNF onboarding test") self.execute() - self.logger.info("Orchestra IMS VNF onboarding test executed") + self.logger.info("Opera vIMS VNF onboarding test finished") if self.criteria is "PASS": return self.EX_OK else: @@ -391,10 +127,3 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): def run(self): kwargs = {} return self.main(**kwargs) - - -if __name__ == '__main__': - test = ImsVnf() - test.deploy_orchestrator() - test.deploy_vnf() - test.clean() diff --git a/functest/tests/unit/opnfv_tests/vnf/ims/test_cloudify_ims.py b/functest/tests/unit/opnfv_tests/vnf/ims/test_cloudify_ims.py index e25816f01..f47ea865e 100644 --- a/functest/tests/unit/opnfv_tests/vnf/ims/test_cloudify_ims.py +++ b/functest/tests/unit/opnfv_tests/vnf/ims/test_cloudify_ims.py @@ -13,7 +13,7 @@ import mock from functest.opnfv_tests.vnf.ims import cloudify_ims -class ImsVnfTesting(unittest.TestCase): +class CloudifyImsTesting(unittest.TestCase): logging.disable(logging.CRITICAL) @@ -22,7 +22,7 @@ class ImsVnfTesting(unittest.TestCase): 'os.makedirs'), \ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.' 'get_config', return_value='config_value'): - self.ims_vnf = cloudify_ims.ImsVnf() + self.ims_vnf = cloudify_ims.CloudifyIms() self.neutron_client = mock.Mock() self.glance_client = mock.Mock() self.keystone_client = mock.Mock() @@ -419,94 +419,46 @@ class ImsVnfTesting(unittest.TestCase): self.ims_vnf.test_vnf() self.assertTrue(msg in context.exception) - def test_test_vnf_create_number_failure(self): - with mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.' - 'os.popen') as m, \ - mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.' - 'requests.get'), \ - mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.' - 'requests.post', - return_value=self.mock_post), \ - self.assertRaises(Exception) as context: - mock_obj = mock.Mock() - attrs = {'read.return_value': 'test_ip\n'} - mock_obj.configure_mock(**attrs) - m.return_value = mock_obj - - self.ims_vnf.test_vnf() - - msg = "Unable to create a number:" - self.assertTrue(msg in context.exception) - - def _get_post_status(self, url, cookies='', data=''): - ellis_url = "http://test_ellis_ip/session" - if url == ellis_url: - return self.mock_post_200 - return self.mock_post - def test_test_vnf_fail(self): with mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.' - 'os.popen') as m, \ - mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.' - 'requests.get') as mock_get, \ - mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.' - 'requests.post', - side_effect=self._get_post_status), \ - mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.' - 'ft_utils.get_resolvconf_ns'), \ - mock.patch('__builtin__.open', mock.mock_open()), \ - mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.' - 'subprocess.call'), \ - mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.' - 'os.remove'), \ - mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.' - 'json.load', return_value=''): - mock_obj = mock.Mock() - attrs = {'read.return_value': 'test_ip\n'} - mock_obj.configure_mock(**attrs) - m.return_value = mock_obj + 'os.popen'), \ + mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.' + 'requests.get') as mock_get, \ + mock.patch.object(self.ims_vnf, 'config_ellis'), \ + mock.patch.object(self.ims_vnf, + 'run_clearwater_live_test') as clearwater_obj: + clearwater_obj.return_value = '' - mock_obj2 = mock.Mock() - attrs = {'json.return_value': {'outputs': - {'dns_ip': 'test_dns_ip', - 'ellis_ip': 'test_ellis_ip'}}} - mock_obj2.configure_mock(**attrs) - mock_get.return_value = mock_obj2 + mock_obj2 = mock.Mock() + attrs = {'json.return_value': {'outputs': + {'dns_ip': 'test_dns_ip', + 'ellis_ip': 'test_ellis_ip'}}} + mock_obj2.configure_mock(**attrs) + mock_get.return_value = mock_obj2 - self.assertEqual(self.ims_vnf.test_vnf(), - {'status': 'FAIL', 'result': ''}) + self.assertEqual(self.ims_vnf.test_vnf(), + {'status': 'FAIL', 'result': ''}) def test_test_vnf_pass(self): with mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.' - 'os.popen') as m, \ - mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.' - 'requests.get') as mock_get, \ - mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.' - 'requests.post', - side_effect=self._get_post_status), \ - mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.' - 'ft_utils.get_resolvconf_ns'), \ - mock.patch('__builtin__.open', mock.mock_open()), \ - mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.' - 'subprocess.call'), \ - mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.' - 'os.remove'), \ - mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.' - 'json.load', return_value='vims_test_result'): - mock_obj = mock.Mock() - attrs = {'read.return_value': 'test_ip\n'} - mock_obj.configure_mock(**attrs) - m.return_value = mock_obj - - mock_obj2 = mock.Mock() - attrs = {'json.return_value': {'outputs': - {'dns_ip': 'test_dns_ip', - 'ellis_ip': 'test_ellis_ip'}}} - mock_obj2.configure_mock(**attrs) - mock_get.return_value = mock_obj2 - - self.assertEqual(self.ims_vnf.test_vnf(), - {'status': 'PASS', 'result': 'vims_test_result'}) + 'os.popen'), \ + mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.' + 'requests.get') as mock_get, \ + mock.patch.object(self.ims_vnf, 'config_ellis'), \ + mock.patch.object(self.ims_vnf, + 'run_clearwater_live_test') as clearwater_obj: + clearwater_obj.return_value = 'vims_test_result' + + mock_obj2 = mock.Mock() + attrs = {'json.return_value': {'outputs': + {'dns_ip': 'test_dns_ip', + 'ellis_ip': 'test_ellis_ip'}}} + mock_obj2.configure_mock(**attrs) + mock_get.return_value = mock_obj2 + + self.assertEqual(self.ims_vnf.test_vnf(), + {'status': 'PASS', + 'result': 'vims_test_result'}) def test_download_and_add_image_on_glance_incorrect_url(self): with mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.' diff --git a/functest/tests/unit/opnfv_tests/vnf/ims/test_ims_base.by b/functest/tests/unit/opnfv_tests/vnf/ims/test_ims_base.by new file mode 100644 index 000000000..9440bcdf3 --- /dev/null +++ b/functest/tests/unit/opnfv_tests/vnf/ims/test_ims_base.by @@ -0,0 +1,58 @@ +#!/usr/bin/env python + +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 + +import logging +import unittest + +import mock + +from functest.opnfv_tests.vnf.ims import ims_base + + +class ClearwaterOnBoardingBaseTesting(unittest.TestCase): + + logging.disable(logging.CRITICAL) + + def setUp(self): + with mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.' + 'os.makedirs'): + self.ims_vnf = ims_base.ClearwaterOnBoardingBase() + + self.mock_post = mock.Mock() + attrs = {'status_code': 201, + 'cookies': ""} + self.mock_post.configure_mock(**attrs) + + self.mock_post_200 = mock.Mock() + attrs = {'status_code': 200, + 'cookies': ""} + self.mock_post_200.configure_mock(**attrs) + + self.mock_post_500 = mock.Mock() + attrs = {'status_code': 500, + 'cookies': ""} + self.mock_post_200.configure_mock(**attrs) + + def test_create_ellis_number_failure(self): + with mock.patch('functest.opnfv_tests.vnf.ims.ims_base.' + 'requests.post', + return_value=self.mock_post_500), \ + self.assertRaises(Exception) as context: + self.ims_vnf.create_ellis_number() + + msg = "Unable to create a number:" + self.assertTrue(msg in context.exception) + + def _get_post_status(self, url, cookies='', data=''): + ellis_url = "http://test_ellis_ip/session" + if url == ellis_url: + return self.mock_post_200 + return self.mock_post + + +if __name__ == "__main__": + unittest.main(verbosity=2) |