Merge "vIMS deployment and cleanup"
authorboucherv <valentin.boucher@orange.com>
Mon, 5 Oct 2015 08:15:40 +0000 (08:15 +0000)
committerGerrit Code Review <gerrit@172.30.200.206>
Mon, 5 Oct 2015 08:15:40 +0000 (08:15 +0000)
testcases/config_functest.yaml
testcases/functest_utils.py
testcases/vIMS/CI/create_venv.sh [new file with mode: 0755]
testcases/vIMS/CI/requirements.pip [new file with mode: 0644]
testcases/vIMS/CI/vIMS.py [new file with mode: 0644]

index c38b460..e8ee6d9 100644 (file)
@@ -1,4 +1,3 @@
----
 general:
     directories:
         # Relative to the path where the repo is cloned:
@@ -6,7 +5,9 @@ general:
         dir_odl:        testcases/Controllers/ODL/CI/
         dir_rally:      testcases/VIM/OpenStack/CI/libraries/
         dir_rally_scn:  testcases/VIM/OpenStack/CI/suites/
+        dir_vIMS:       testcases/vIMS/CI/
         # Relative to $HOME:
+        dir_vIMS_data: functest/vIMS_data/ # $HOME/functest/vIMS_data/
         dir_rally_res:  functest/results/ # $HOME/functest/results
         dir_rally_repo: functest/Rally_repo/ # $HOME/Rally_repo/
         dir_rally_inst: .rally/  # $HOME/.rally/ usually
@@ -38,5 +39,53 @@ vping:
     ip_1: 192.168.120.30
     ip_2: 192.168.120.40
 
+vIMS:
+    general:
+        tenant_name: vIMS
+        tenant_description: vIMS Functionality Testing
+        base_image_url: http://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-amd64-disk1.img
+        base_image_name: ubuntu_14.04
+    cloudify:
+        blueprint:
+            url: https://github.com/cloudify-cosmo/cloudify-manager-blueprints.git
+            branch: "3.2-build"
+            file_name: "openstack-manager-blueprint.yaml"
+        inputs:
+            keystone_username: ""
+            keystone_password: ""
+            keystone_tenant_name: ""
+            keystone_url: ""
+            manager_public_key_name: 'cloudify-manager'
+            agent_public_key_name: 'cloudify-agent'
+            image_id: ""
+            flavor_id: "2"
+            external_network_name: ""
+            use_existing_manager_keypair: false
+            use_existing_agent_keypair: false
+            manager_server_name: cloudify-management-server
+            manager_server_user: ubuntu
+            manager_security_group_name: cloudify-sg-manager
+            agents_security_group_name: cloudify-sg-agents
+            manager_private_key_path: ~/.ssh/cloudify-manager-kp.pem
+            agent_private_key_path: ~/.ssh/cloudify-agent-kp.pem
+            agents_user: ubuntu
+            nova_url: ""
+            neutron_url: ""
+            resources_prefix: ""
+        inputs_path: openstack/inputs.yaml
+    clearwater:
+        blueprint:
+            file_name: 'openstack-blueprint.yaml'
+            name: "clearwater-opnfv"
+            destination_folder: "opnfv-cloudify-clearwater"
+            url: 'https://github.com/Orange-OpenSource/opnfv-cloudify-clearwater.git'
+            branch: "master"
+        deployment-name: 'clearwater-opnfv'
+        inputs:
+            image_id: ''
+            flavor_id: ''
+            agent_user: 'ubuntu'
+            external_network_name: ''
+            public_domain: clearwater.opnfv
 results:
-    test_db_url: http://213.77.62.197
+    test_db_url: http://213.77.62.197
\ No newline at end of file
index 1012713..6d60fbc 100644 (file)
@@ -1,6 +1,7 @@
 #!/usr/bin/env python
 #
 # jose.lausuch@ericsson.com
+# valentin.boucher@orange.com
 # 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
@@ -217,8 +218,27 @@ def get_network_list(neutron_client):
     else :
         return network_list
 
+def get_external_net(neutron_client):
+    for network in neutron_client.list_networks()['networks']:
+        if network['router:external']:
+            return network['name']
+    return False
+
+def update_sg_quota(neutron_client, tenant_id, sg_quota, sg_rule_quota):
+    json_body = {"quota": {
+        "security_group": sg_quota,
+        "security_group_rule": sg_rule_quota
+    }}
+
+    try:
+        quota = neutron_client.update_quota(tenant_id=tenant_id, body=json_body)
+        return True
+    except:
+        print "Error:", sys.exc_info()[0]
+        return False
 
 ################# GLANCE #################
+
 def get_image_id(glance_client, image_name):
     images = glance_client.images.list()
     id = ''
@@ -228,10 +248,10 @@ def get_image_id(glance_client, image_name):
             break
     return id
 
-def create_glance_image(glance_client, image_name, file_path):
+def create_glance_image(glance_client, image_name, file_path, is_public=True):
     try:
         with open(file_path) as fimage:
-            image = glance_client.images.create(name=image_name, is_public=True, disk_format="qcow2",
+            image = glance_client.images.create(name=image_name, is_public=is_public, disk_format="qcow2",
                              container_format="bare", data=fimage)
         return image.id
     except:
@@ -282,6 +302,22 @@ def delete_tenant(keystone_client, tenant_id):
         print "Error:", sys.exc_info()[0]
         return False
 
+def create_user(keystone_client, user_name, user_password, user_email, tenant_id):
+    try:
+        user = keystone_client.users.create(user_name, user_password, user_email, tenant_id, enabled=True)
+        return user.id
+    except:
+        print "Error:", sys.exc_info()[0]
+        return False
+
+def delete_user(keystone_client, user_id):
+    try:
+        tenant = keystone_client.users.delete(user_id)
+        return True
+    except:
+        print "Error:", sys.exc_info()[0]
+        return False
+
 def add_role_user(keystone_client, user_id, role_id, tenant_id):
     try:
         keystone_client.roles.add_user_role(user_id, role_id, tenant_id)
diff --git a/testcases/vIMS/CI/create_venv.sh b/testcases/vIMS/CI/create_venv.sh
new file mode 100755 (executable)
index 0000000..15294f7
--- /dev/null
@@ -0,0 +1,36 @@
+#!/bin/bash -e
+
+# Script checks that venv exists. If it doesn't it will be created
+# It requires python2.7 and virtualenv packages installed
+
+BASEDIR=`dirname $0`
+VENV_PATH=$1
+VENV_NAME="venv_cloudify"
+function venv_install() {
+    if command -v virtualenv-2.7; then
+        virtualenv-2.7 $1
+    elif command -v virtualenv2; then
+        virtualenv2 $1
+    elif command -v virtualenv; then
+        virtualenv $1
+    else
+        echo Cannot find virtualenv command.
+        return 1
+    fi
+}
+
+# exit when something goes wrong during venv install
+set -e
+if [ ! -d "$VENV_PATH/$VENV_NAME" ]; then
+    venv_install $VENV_PATH/$VENV_NAME
+    echo "Virtualenv" + $VENV_NAME + "created."
+fi
+
+if [ ! -f "$VENV_PATH/$VENV_NAME/updated" -o $BASEDIR/requirements.pip -nt $VENV_PATH/$VENV_NAME/updated ]; then
+    source $VENV_PATH/$VENV_NAME/bin/activate
+    pip install -r $BASEDIR/requirements.pip
+    touch $VENV_PATH/$VENV_NAME/updated
+    echo "Requirements installed."
+    deactivate
+fi
+set +e
diff --git a/testcases/vIMS/CI/requirements.pip b/testcases/vIMS/CI/requirements.pip
new file mode 100644 (file)
index 0000000..5d13172
--- /dev/null
@@ -0,0 +1 @@
+cloudify==3.2
\ No newline at end of file
diff --git a/testcases/vIMS/CI/vIMS.py b/testcases/vIMS/CI/vIMS.py
new file mode 100644 (file)
index 0000000..d2d10f3
--- /dev/null
@@ -0,0 +1,332 @@
+#!/usr/bin/python
+# coding: utf8
+#######################################################################
+#
+#   Copyright (c) 2015 Orange
+#   valentin.boucher@orange.com
+#
+# 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 os, time, subprocess, logging, argparse, yaml, pprint, sys, shutil
+from git import Repo
+import keystoneclient.v2_0.client as ksclient
+import glanceclient.client as glclient
+import novaclient.client as nvclient
+from neutronclient.v2_0 import client as ntclient
+
+import urllib
+pp = pprint.PrettyPrinter(indent=4)
+
+
+parser = argparse.ArgumentParser()
+parser.add_argument("repo_path", help="Path to the repository")
+parser.add_argument("-d", "--debug", help="Debug mode",  action="store_true")
+args = parser.parse_args()
+
+sys.path.append(args.repo_path + "testcases/")
+
+import functest_utils
+
+""" logging configuration """
+logger = logging.getLogger('vIMS')
+logger.setLevel(logging.DEBUG)
+
+ch = logging.StreamHandler()
+if args.debug:
+    ch.setLevel(logging.DEBUG)
+else:
+    ch.setLevel(logging.INFO)
+formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+ch.setFormatter(formatter)
+logger.addHandler(ch)
+
+
+HOME = os.environ['HOME']+"/"
+# with open(args.repo_path+"config_functest.yaml") as f:
+with open(args.repo_path + "testcases/config_functest.yaml") as f:
+    functest_yaml = yaml.safe_load(f)
+f.close()
+
+# Cloudify parameters
+REPO_PATH = args.repo_path
+HOME = os.environ['HOME']+"/"
+VIMS_DIR = REPO_PATH + functest_yaml.get("general").get("directories").get("dir_vIMS")
+VIMS_DATA_DIR = HOME + functest_yaml.get("general").get("directories").get("dir_vIMS_data")
+
+TENANT_NAME = functest_yaml.get("vIMS").get("general").get("tenant_name")
+TENANT_DESCRIPTION = functest_yaml.get("vIMS").get("general").get("tenant_description")
+BASE_IMAGE_URL = functest_yaml.get("vIMS").get("general").get("base_image_url")
+BASE_IMAGE_NAME = functest_yaml.get("vIMS").get("general").get("base_image_name")
+GLANCE_IMAGE_NAME = functest_yaml.get("vIMS").get("cloudify").get("inputs").get("image_id")
+
+CFY_MANAGER_BLUEPRINT = functest_yaml.get("vIMS").get("cloudify").get("blueprint")
+CFY_INPUTS =  functest_yaml.get("vIMS").get("cloudify").get("inputs")
+CFY_INPUTS_PATH =  functest_yaml.get("vIMS").get("cloudify").get("inputs_path")
+
+CW_BLUEPRINT = functest_yaml.get("vIMS").get("clearwater").get("blueprint")
+CW_DEPLOYMENT_NAME = functest_yaml.get("vIMS").get("clearwater").get("deployment-name")
+CW_INPUTS =  functest_yaml.get("vIMS").get("clearwater").get("inputs")
+CW_DOMAIN_NAME =  functest_yaml.get("vIMS").get("clearwater").get("inputs").get("public_domain")
+
+
+def pMsg(value):
+    """pretty printing"""
+    pp.pprint(value)
+
+def download_and_add_image_on_glance(glance, image_name, image_url):
+    dest_path = VIMS_DATA_DIR + "tmp/"
+    file_name = image_url.rsplit('/')[-1]
+    if not functest_utils.download_url(image_url, dest_path):
+        logger.error("Failed to download image %s" %file_name)
+        return False
+
+    image = functest_utils.create_glance_image(glance, image_name, dest_path + file_name)
+    if not image:
+        logger.error("Failed to upload image on glance")
+        return False
+
+    return image
+
+def download_blueprints(blueprint_url, branch, dest_path):
+    if os.path.exists(dest_path):
+        shutil.rmtree(dest_path)
+    try:
+        Repo.clone_from(blueprint_url, dest_path, branch=branch)
+        return True
+    except:
+        return False
+
+def initialize_deployments():
+    if not os.path.exists(VIMS_DATA_DIR):
+        os.makedirs(VIMS_DATA_DIR)
+
+    ks_creds = functest_utils.get_credentials("keystone")
+    nv_creds = functest_utils.get_credentials("nova")
+    nt_creds = functest_utils.get_credentials("neutron")
+
+    logger.info("Prepare OpenStack plateform (create tenant and user)")
+    keystone = ksclient.Client(**ks_creds)
+
+    user_id = functest_utils.get_user_id(keystone, ks_creds['username'])
+    if user_id == '':
+        logger.error("Error : Failed to get id of %s user" %ks_creds['username'])
+        exit(-1)
+
+    tenant_id = functest_utils.create_tenant(keystone, TENANT_NAME, TENANT_DESCRIPTION)
+    if tenant_id == '':
+        logger.error("Error : Failed to create %s tenant" %TENANT_NAME)
+        exit(-1)
+
+    role_name = "admin"
+    role_id = functest_utils.get_role_id(keystone, role_name)
+    if role_id == '':
+        logger.error("Error : Failed to get id for %s role" %role_name)
+
+    if not functest_utils.add_role_user(keystone, user_id, role_id, tenant_id):
+        logger.error("Error : Failed to add %s on tenant" %ks_creds['username'])
+
+    user_id = functest_utils.create_user(keystone, TENANT_NAME, TENANT_NAME, None, tenant_id)
+    if user_id == '':
+        logger.error("Error : Failed to create %s user" %TENANT_NAME)
+
+    logger.info("Update OpenStack creds informations")
+    ks_creds.update({
+        "username": TENANT_NAME,
+        "password": TENANT_NAME,
+        "tenant_name": TENANT_NAME,
+        })
+
+    nt_creds.update({
+        "tenant_name": TENANT_NAME,
+        })
+
+    nv_creds.update({
+        "project_id": TENANT_NAME,
+        })
+
+    logger.info("Upload ubuntu image if it doesn't exist")
+    glance_endpoint = keystone.service_catalog.url_for(service_type='image',
+                                                   endpoint_type='publicURL')
+    glance = glclient.Client(1, glance_endpoint, token=keystone.auth_token)
+
+    image_id = functest_utils.get_image_id(glance, BASE_IMAGE_NAME)
+    if image_id == '':
+        logger.info("""%s image doesn't exist on glance repository.
+                        Try downloading this image and upload on glance !""" %BASE_IMAGE_NAME)
+        image_id = download_and_add_image_on_glance(glance, BASE_IMAGE_NAME, BASE_IMAGE_URL)
+
+    if image_id == '':
+        logger.error("Error : Failed to find or upload required OS image for this deployment" %flavor_name)
+        exit(-1)
+
+    logger.info("Collect flavor id for cloudify and clearwater VMs")
+    nova = nvclient.Client("2", **nv_creds)
+
+    flavor_name = "m1.small"
+    flavor_id = functest_utils.get_flavor_id(nova, flavor_name)
+    if flavor_id == '':
+        logger.error("Failed to find %s flavor. Try with ram range requirement !" %flavor_name)
+        flavor_id = get_flavor_id_by_ram_range(nova, 1792, 2048)
+
+    if flavor_id == '':
+        logger.error("Failed to find required flavor for this deployment" %flavor_name)
+        exit(-1)
+
+    logger.info("Update security group quota for this tenant")
+    neutron = ntclient.Client(**nt_creds)
+    if not functest_utils.update_sg_quota(neutron, tenant_id, 50, 100):
+        logger.error("Failed to update security group quota for tenant %s" %TENANT_NAME)
+        exit(-1)
+
+    ext_net = functest_utils.get_external_net(neutron)
+    if not ext_net:
+        logger.error("Failed to get external network")
+        exit(-1)
+
+    logger.info("Update inputs informations")
+    CFY_INPUTS['image_id'] = image_id
+    CFY_INPUTS['flavor_id'] = flavor_id
+    CFY_INPUTS['external_network_name'] = ext_net
+
+    CW_INPUTS['image_id'] = image_id
+    CW_INPUTS['flavor_id'] = flavor_id
+    CW_INPUTS['external_network_name'] = ext_net
+
+    CFY_INPUTS['keystone_username'] = ks_creds['username']
+    CFY_INPUTS['keystone_password'] = ks_creds['password']
+    CFY_INPUTS['keystone_url'] = ks_creds['auth_url']
+    CFY_INPUTS['keystone_tenant_name'] = ks_creds['tenant_name']
+
+    logger.info("Prepare virtualenv for cloudify-cli")
+    cmd = "chmod +x " + VIMS_DIR + "create_venv.sh"
+    functest_utils.execute_command(cmd,logger)
+    cmd = VIMS_DIR + "create_venv.sh " + VIMS_DATA_DIR
+    functest_utils.execute_command(cmd,logger)
+
+def cleanup_deployments():
+    ks_creds = functest_utils.get_credentials("keystone")
+
+    keystone = ksclient.Client(**ks_creds)
+
+    logger.info("Removing %s tenant .." %CFY_INPUTS['keystone_tenant_name'])
+    tenant_id = functest_utils.get_tenant_id(keystone, CFY_INPUTS['keystone_tenant_name'])
+    if tenant_id == '':
+        logger.error("Error : Failed to get id of %s tenant" %CFY_INPUTS['keystone_tenant_name'])
+    else:
+        if not functest_utils.delete_tenant(keystone, tenant_id):
+            logger.error("Error : Failed to remove %s tenant" %CFY_INPUTS['keystone_tenant_name'])
+
+    logger.info("Removing %s user .." %CFY_INPUTS['keystone_username'])
+    user_id = functest_utils.get_user_id(keystone, CFY_INPUTS['keystone_username'])
+    if user_id == '':
+        logger.error("Error : Failed to get id of %s user" %CFY_INPUTS['keystone_username'])
+    else:
+        if not functest_utils.delete_user(keystone, user_id):
+            logger.error("Error : Failed to remove %s user" %CFY_INPUTS['keystone_username'])
+
+def deploy_cloudify_manager():
+
+    logger.info("Downloading the cloudify manager server blueprint")
+    download_result = download_blueprints(CFY_MANAGER_BLUEPRINT['url'],
+                                                        CFY_MANAGER_BLUEPRINT['branch'],
+                                                        VIMS_DATA_DIR + 'cloudify-manager-blueprint/')
+
+    if not download_result:
+        logger.error("Failed to download manager blueprint")
+        exit(-1)
+
+    logger.info("Writing the inputs file")
+    with open( VIMS_DATA_DIR + 'cloudify-manager-blueprint/' + CFY_INPUTS_PATH, "w") as f:
+        f.write(yaml.dump(CFY_INPUTS, default_style='"') )
+    f.close()
+
+    logger.info("Launching the cloudify-manager deployment")
+    script = "source " + VIMS_DATA_DIR + "venv_cloudify/bin/activate; "
+    script += "cd " + VIMS_DATA_DIR + "; "
+    script += "cfy init -r; "
+    script += "cd cloudify-manager-blueprint/openstack; "
+    script += "cfy local create-requirements -o requirements.txt -p openstack-manager-blueprint.yaml; "
+    script += "pip install -r requirements.txt; "
+    script += "cfy bootstrap --install-plugins -p openstack-manager-blueprint.yaml -i inputs.yaml; "
+    cmd = "/bin/bash -c '" + script + "'"
+    functest_utils.execute_command(cmd, logger)
+
+    logger.info("Cloudify-manager server is UP !")
+
+def undeploy_cloudify_manager():
+
+    logger.info("Launching the cloudify-manager undeployment")
+    script = "source " + VIMS_DATA_DIR + "venv_cloudify/bin/activate; "
+    script += "cd " + VIMS_DATA_DIR + "; "
+    script += "cfy teardown -f; "
+    cmd = "/bin/bash -c '" + script + "'"
+    functest_utils.execute_command(cmd, logger)
+
+    logger.info("Cloudify-manager server has been successfully removed!")
+
+def deploy_clearwater():
+
+    logger.info("Downloading the {0} blueprint".format(CW_BLUEPRINT['file_name']))
+    download_result = download_blueprints(CW_BLUEPRINT['url'], CW_BLUEPRINT['branch'],
+                                              VIMS_DATA_DIR + CW_BLUEPRINT['destination_folder'])
+
+    if not download_result:
+        logger.error("Failed to download blueprint {0}".format(CW_BLUEPRINT['file_name']))
+        exit(-1)
+
+    logger.info("Writing the inputs file")
+    with open(VIMS_DATA_DIR + CW_BLUEPRINT['destination_folder'] + "/inputs.yaml", "w") as f:
+        f.write(yaml.dump(CW_INPUTS, default_style='"') )
+    f.close()
+
+    logger.info("Launching the {0} deployment".format(CW_BLUEPRINT['name']))
+    script = "source " + VIMS_DATA_DIR + "venv_cloudify/bin/activate; "
+    script += "cd " + VIMS_DATA_DIR + CW_BLUEPRINT['destination_folder'] + "; "
+    script += "cfy blueprints upload -b " + CW_BLUEPRINT['name'] + " -p openstack-blueprint.yaml; "
+    script += "cfy deployments create -b " + CW_BLUEPRINT['name'] + " -d " + CW_DEPLOYMENT_NAME + " --inputs inputs.yaml; "
+    script += "cfy executions start -w install -d " + CW_DEPLOYMENT_NAME + "; "
+
+    cmd = "/bin/bash -c '" + script + "'"
+    functest_utils.execute_command(cmd, logger)
+
+    logger.info("Clearwater vIMS is UP !")
+
+def undeploy_clearwater():
+
+    logger.info("Launching the {0} undeployment".format(CW_BLUEPRINT['name']))
+    script = "source " + VIMS_DATA_DIR + "venv_cloudify/bin/activate; "
+    script += "cd " + VIMS_DATA_DIR + "; "
+    script += "cfy executions start -w uninstall -d " + CW_DEPLOYMENT_NAME + "; "
+    script += "cfy deployments delete -d " + CW_DEPLOYMENT_NAME + "; "
+
+    cmd = "/bin/bash -c '" + script + "'"
+    functest_utils.execute_command(cmd, logger)
+
+def test_clearwater():
+
+    script = "source " + VIMS_DATA_DIR + "venv_cloudify/bin/activate; "
+    script += "cd " + VIMS_DATA_DIR + "; "
+    script += "cfy deployments outputs -d clearwater-opnfv | grep Value: | sed \"s/ *Value: //g\";"
+    cmd = "/bin/bash -c '" + script + "'"
+    dns_ip = os.popen(cmd).read()
+    dns_ip = dns_ip.splitlines()[0]
+
+    # Coming soon
+
+def main():
+    initialize_deployments()
+    deploy_cloudify_manager()
+    deploy_clearwater()
+
+    #test_clearwater()
+
+    undeploy_clearwater()
+    undeploy_cloudify_manager()
+    cleanup_deployments()
+
+if __name__ == '__main__':
+    main()
\ No newline at end of file