summaryrefslogtreecommitdiffstats
path: root/docs/_templates
AgeCommit message (Collapse)AuthorFilesLines
2017-10-07Enabling custom style overrides and introducing green linksGeorg Kunz1-1/+1
There is a style-sheet in the docs repo which is supposed to customize the default style, but which was actually never applied. This patchset enables custom overrides of the default style. As one of the custom style changes, this patchset changes the color of hyperlinks to the same green used on www.opnfv.org. Change-Id: I3c8a59e7f0beaf0150915941730f68071a40330a Signed-off-by: Georg Kunz <georg.kunz@ericsson.com>
2017-05-02Misc ChangesShubhamRathi1-0/+15
1. Add sidebar akin to ODL 2. Remove redundant 'OPNFV' from all composite document titles 3. Edit documentation-example for the updated toolchain. Renamed this file as 'addendum.rst'. Eliminated obsolete content. 4. Listed test projects in alphabetic order Change-Id: Ica1c4aa89e3c8f8bcb960fcd4574971960dc52dc Signed-off-by: ShubhamRathi <shubhamiiitbackup@gmail.com>
2017-03-16CSS Changes to layoutShubhamRathi1-0/+5
1. Logo has been scaled up 2. Font has been defaulted to 'Arial' Change-Id: I7d729009649ba59394f5a78c6909b6af21bae0ab Signed-off-by: ShubhamRathi <shubhamiiitbackup@gmail.com>
2017-03-13Add SidebarShubhamRathi1-0/+3
Change-Id: I1425eda919f49cbc82d1ab60ef91324d9afee041 Signed-off-by: ShubhamRathi <shubhamiiitbackup@gmail.com>
href='#n153'>153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
#!/usr/bin/env python

# Copyright (c) 2017 Orange and others.
#
# 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

"""CloudifyIms testcase implementation."""

import logging
import os
import time

from cloudify_rest_client import CloudifyClient
from cloudify_rest_client.executions import Execution
from scp import SCPClient
import yaml

from functest.energy import energy
from functest.opnfv_tests.openstack.snaps import snaps_utils
import functest.opnfv_tests.vnf.ims.clearwater_ims_base as clearwater_ims_base
from functest.utils.constants import CONST

from snaps.config.flavor import FlavorConfig
from snaps.config.image import ImageConfig
from snaps.config.keypair import KeypairConfig
from snaps.config.network import NetworkConfig, PortConfig, SubnetConfig
from snaps.config.router import RouterConfig
from snaps.config.security_group import (
    Direction, Protocol, SecurityGroupConfig, SecurityGroupRuleConfig)
from snaps.config.vm_inst import FloatingIpConfig, VmInstanceConfig

from snaps.openstack.create_flavor import OpenStackFlavor
from snaps.openstack.create_image import OpenStackImage
from snaps.openstack.create_instance import OpenStackVmInstance
from snaps.openstack.create_keypairs import OpenStackKeypair
from snaps.openstack.create_network import OpenStackNetwork
from snaps.openstack.create_router import OpenStackRouter
from snaps.openstack.create_security_group import OpenStackSecurityGroup
from snaps.openstack.utils import keystone_utils


__author__ = "Valentin Boucher <valentin.boucher@orange.com>"


class CloudifyIms(clearwater_ims_base.ClearwaterOnBoardingBase):
    """Clearwater vIMS deployed with Cloudify Orchestrator Case."""

    __logger = logging.getLogger(__name__)

    def __init__(self, **kwargs):
        """Initialize CloudifyIms testcase object."""
        if "case_name" not in kwargs:
            kwargs["case_name"] = "cloudify_ims"
        super(CloudifyIms, self).__init__(**kwargs)

        # Retrieve the configuration
        try:
            self.config = CONST.__getattribute__(
                'vnf_{}_config'.format(self.case_name))
        except Exception:
            raise Exception("VNF config file not found")

        config_file = os.path.join(self.case_dir, self.config)
        self.orchestrator = dict(
            requirements=get_config("orchestrator.requirements", config_file),
        )
        self.details['orchestrator'] = dict(
            name=get_config("orchestrator.name", config_file),
            version=get_config("orchestrator.version", config_file),
            status='ERROR',
            result=''
        )
        self.__logger.debug("Orchestrator configuration %s", self.orchestrator)
        self.vnf = dict(
            descriptor=get_config("vnf.descriptor", config_file),
            inputs=get_config("vnf.inputs", config_file),
            requirements=get_config("vnf.requirements", config_file)
        )
        self.details['vnf'] = dict(
            descriptor_version=self.vnf['descriptor']['version'],
            name=get_config("vnf.name", config_file),
            version=get_config("vnf.version", config_file),
        )
        self.__logger.debug("VNF configuration: %s", self.vnf)

        self.details['test_vnf'] = dict(
            name=get_config("vnf_test_suite.name", config_file),
            version=get_config("vnf_test_suite.version", config_file)
        )
        self.images = get_config("tenant_images", config_file)
        self.__logger.info("Images needed for vIMS: %s", self.images)

    def prepare(self):
        """Prepare testscase (Additional pre-configuration steps)."""
        super(CloudifyIms, self).prepare()

        self.__logger.info("Additional pre-configuration steps")

        compute_quotas = self.os_project.get_compute_quotas()
        network_quotas = self.os_project.get_network_quotas()

        for key, value in (
                self.vnf['requirements']['compute_quotas'].items()):
            setattr(compute_quotas, key, value)

        for key, value in (
                self.vnf['requirements']['network_quotas'].items()):
            setattr(network_quotas, key, value)

        compute_quotas = self.os_project.update_compute_quotas(compute_quotas)
        network_quotas = self.os_project.update_network_quotas(network_quotas)

        # needs some images
        self.__logger.info("Upload some OS images if it doesn't exist")
        for image_name, image_file in self.images.iteritems():
            self.__logger.info("image: %s, file: %s", image_name, image_file)
            if image_file and image_name:
                image_creator = OpenStackImage(
                    self.snaps_creds,
                    ImageConfig(
                        name=image_name, image_user='cloud',
                        img_format='qcow2', image_file=image_file))
                image_creator.create()
                self.created_object.append(image_creator)

    def deploy_orchestrator(self):
        """
        Deploy Cloudify Manager.

        network, security group, fip, VM creation
        """
        # network creation

        start_time = time.time()
        self.__logger.info("Creating keypair ...")
        kp_file = os.path.join(self.data_dir, "cloudify_ims.pem")
        keypair_settings = KeypairConfig(
            name='cloudify_ims_kp-{}'.format(self.uuid),
            private_filepath=kp_file)
        keypair_creator = OpenStackKeypair(self.snaps_creds, keypair_settings)
        keypair_creator.create()
        self.created_object.append(keypair_creator)

        self.__logger.info("Creating full network ...")
        subnet_settings = SubnetConfig(
            name='cloudify_ims_subnet-{}'.format(self.uuid),
            cidr='10.67.79.0/24')
        network_settings = NetworkConfig(
            name='cloudify_ims_network-{}'.format(self.uuid),
            subnet_settings=[subnet_settings])
        network_creator = OpenStackNetwork(self.snaps_creds, network_settings)
        network_creator.create()
        self.created_object.append(network_creator)
        ext_net_name = snaps_utils.get_ext_net_name(self.snaps_creds)
        router_creator = OpenStackRouter(
            self.snaps_creds,
            RouterConfig(
                name='cloudify_ims_router-{}'.format(self.uuid),
                external_gateway=ext_net_name,
                internal_subnets=[subnet_settings.name]))
        router_creator.create()
        self.created_object.append(router_creator)

        # security group creation
        self.__logger.info("Creating security group for cloudify manager vm")
        sg_rules = list()
        sg_rules.append(
            SecurityGroupRuleConfig(
                sec_grp_name="sg-cloudify-manager-{}".format(self.uuid),
                direction=Direction.ingress, protocol=Protocol.tcp,
                port_range_min=1, port_range_max=65535))
        sg_rules.append(
            SecurityGroupRuleConfig(
                sec_grp_name="sg-cloudify-manager-{}".format(self.uuid),
                direction=Direction.ingress, protocol=Protocol.udp,
                port_range_min=1, port_range_max=65535))

        security_group_creator = OpenStackSecurityGroup(
            self.snaps_creds,
            SecurityGroupConfig(
                name="sg-cloudify-manager-{}".format(self.uuid),
                rule_settings=sg_rules))

        security_group_creator.create()
        self.created_object.append(security_group_creator)

        # orchestrator VM flavor
        self.__logger.info("Get or create flavor for cloudify manager vm ...")

        flavor_settings = FlavorConfig(
            name=self.orchestrator['requirements']['flavor']['name'],
            ram=self.orchestrator['requirements']['flavor']['ram_min'],
            disk=50,
            vcpus=2)
        flavor_creator = OpenStackFlavor(self.snaps_creds, flavor_settings)
        flavor_creator.create()
        self.created_object.append(flavor_creator)
        image_settings = ImageConfig(
            name=self.orchestrator['requirements']['os_image'],
            image_user='centos',
            exists=True)

        port_settings = PortConfig(
            name='cloudify_manager_port-{}'.format(self.uuid),
            network_name=network_settings.name)

        manager_settings = VmInstanceConfig(
            name='cloudify_manager-{}'.format(self.uuid),
            flavor=flavor_settings.name,
            port_settings=[port_settings],
            security_group_names=[
                security_group_creator.sec_grp_settings.name],
            floating_ip_settings=[FloatingIpConfig(
                name='cloudify_manager_fip-{}'.format(self.uuid),
                port_name=port_settings.name,
                router_name=router_creator.router_settings.name)])

        manager_creator = OpenStackVmInstance(
            self.snaps_creds, manager_settings, image_settings,
            keypair_settings)

        self.__logger.info("Creating cloudify manager VM")
        manager_creator.create()
        self.created_object.append(manager_creator)

        public_auth_url = keystone_utils.get_endpoint(
            self.snaps_creds, 'identity')

        cfy_creds = dict(
            keystone_username=self.snaps_creds.username,
            keystone_password=self.snaps_creds.password,
            keystone_tenant_name=self.snaps_creds.project_name,
            keystone_url=public_auth_url,
            region=self.snaps_creds.region_name)
        self.__logger.info("Set creds for cloudify manager %s", cfy_creds)

        cfy_client = CloudifyClient(
            host=manager_creator.get_floating_ip().ip,
            username='admin', password='admin', tenant='default_tenant')

        self.orchestrator['object'] = cfy_client

        self.__logger.info("Attemps running status of the Manager")
        cfy_status = None
        retry = 10
        while str(cfy_status) != 'running' and retry:
            try:
                cfy_status = cfy_client.manager.get_status()['status']
                self.__logger.debug("The current manager status is %s",
                                    cfy_status)
            except Exception:  # pylint: disable=broad-except
                self.__logger.exception(
                    "Cloudify Manager isn't up and running. Retrying ...")
            retry = retry - 1
            time.sleep(30)

        if str(cfy_status) == 'running':
            self.__logger.info("Cloudify Manager is up and running")
        else:
            raise Exception("Cloudify Manager isn't up and running")

        self.__logger.info("Put OpenStack creds in manager")
        secrets_list = cfy_client.secrets.list()
        for k, val in cfy_creds.iteritems():
            if not any(d.get('key', None) == k for d in secrets_list):
                cfy_client.secrets.create(k, val)
            else:
                cfy_client.secrets.update(k, val)

        duration = time.time() - start_time

        self.__logger.info("Put private keypair in manager")
        if manager_creator.vm_ssh_active(block=True):
            ssh = manager_creator.ssh_client()
            scp = SCPClient(ssh.get_transport(), socket_timeout=15.0)
            scp.put(kp_file, '~/')
            cmd = "sudo cp ~/cloudify_ims.pem /etc/cloudify/"
            run_blocking_ssh_command(ssh, cmd)
            cmd = "sudo chmod 444 /etc/cloudify/cloudify_ims.pem"
            run_blocking_ssh_command(ssh, cmd)
            cmd = "sudo yum install -y gcc python-devel"
            run_blocking_ssh_command(ssh, cmd, "Unable to install packages \
                                                on manager")

        self.details['orchestrator'].update(status='PASS', duration=duration)

        self.vnf['inputs'].update(dict(
            external_network_name=ext_net_name,
            network_name=network_settings.name,
            key_pair_name=keypair_settings.name
        ))
        self.result = 1/3 * 100
        return True

    def deploy_vnf(self):
        """Deploy Clearwater IMS."""
        start_time = time.time()

        self.__logger.info("Upload VNFD")
        cfy_client = self.orchestrator['object']
        descriptor = self.vnf['descriptor']
        cfy_client.blueprints.publish_archive(descriptor.get('url'),
                                              descriptor.get('name'),
                                              descriptor.get('file_name'))

        self.__logger.info("Get or create flavor for all clearwater vm")
        flavor_settings = FlavorConfig(
            name=self.vnf['requirements']['flavor']['name'],
            ram=self.vnf['requirements']['flavor']['ram_min'],
            disk=25,
            vcpus=1)
        flavor_creator = OpenStackFlavor(self.snaps_creds, flavor_settings)
        flavor_creator.create()
        self.created_object.append(flavor_creator)

        self.vnf['inputs'].update(dict(
            flavor_id=self.vnf['requirements']['flavor']['name'],
        ))

        self.__logger.info("Create VNF Instance")
        cfy_client.deployments.create(descriptor.get('name'),
                                      descriptor.get('name'),
                                      self.vnf.get('inputs'))

        wait_for_execution(cfy_client,
                           _get_deployment_environment_creation_execution(
                               cfy_client, descriptor.get('name')),
                           self.__logger,
                           timeout=300)

        self.__logger.info("Start the VNF Instance deployment")
        execution = cfy_client.executions.start(descriptor.get('name'),
                                                'install')
        # Show execution log
        execution = wait_for_execution(cfy_client, execution, self.__logger)

        duration = time.time() - start_time

        self.__logger.info(execution)
        if execution.status == 'terminated':
            self.details['vnf'].update(status='PASS', duration=duration)
            self.result += 1/3 * 100
            result = True
        else:
            self.details['vnf'].update(status='FAIL', duration=duration)
            result = False
        return result

    def test_vnf(self):
        """Run test on clearwater ims instance."""
        start_time = time.time()

        cfy_client = self.orchestrator['object']

        outputs = cfy_client.deployments.outputs.get(
            self.vnf['descriptor'].get('name'))['outputs']
        dns_ip = outputs['dns_ip']
        ellis_ip = outputs['ellis_ip']
        self.config_ellis(ellis_ip)

        if not dns_ip:
            return False

        vims_test_result = self.run_clearwater_live_test(
            dns_ip=dns_ip,
            public_domain=self.vnf['inputs']["public_domain"])
        duration = time.time() - start_time
        short_result, nb_test = sig_test_format(vims_test_result)
        self.__logger.info(short_result)
        self.details['test_vnf'].update(result=short_result,
                                        full_result=vims_test_result,
                                        duration=duration)
        try:
            vnf_test_rate = short_result['passed'] / nb_test
            # orchestrator + vnf + test_vnf
            self.result += vnf_test_rate / 3 * 100
        except ZeroDivisionError:
            self.__logger.error("No test has been executed")
            self.details['test_vnf'].update(status='FAIL')
            return False

        return True

    def clean(self):
        """Clean created objects/functions."""
        try:
            cfy_client = self.orchestrator['object']
            dep_name = self.vnf['descriptor'].get('name')
            # kill existing execution
            self.__logger.info('Deleting the current deployment')
            exec_list = cfy_client.executions.list(dep_name)
            for execution in exec_list:
                if execution['status'] == "started":
                    try:
                        cfy_client.executions.cancel(execution['id'],
                                                     force=True)
                    except:  # pylint: disable=broad-except
                        self.__logger.warn("Can't cancel the current exec")

            execution = cfy_client.executions.start(
                dep_name,
                'uninstall',
                parameters=dict(ignore_failure=True),
                force=True)

            wait_for_execution(cfy_client, execution, self.__logger)
            cfy_client.deployments.delete(self.vnf['descriptor'].get('name'))
            cfy_client.blueprints.delete(self.vnf['descriptor'].get('name'))
        except:  # pylint: disable=broad-except
            self.__logger.warn("Some issue during the undeployment ..")
            self.__logger.warn("Tenant clean continue ..")

        super(CloudifyIms, self).clean()

    @energy.enable_recording
    def run(self, **kwargs):
        """Execute CloudifyIms test case."""
        return super(CloudifyIms, self).run(**kwargs)


# ----------------------------------------------------------
#
#               YAML UTILS
#
# -----------------------------------------------------------
def get_config(parameter, file_path):
    """
    Get config parameter.

    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_path) as config_file:
        file_yaml = yaml.safe_load(config_file)
    config_file.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 wait_for_execution(client, execution, logger, timeout=1500, ):
    """Wait for a workflow execution on Cloudify Manager."""
    # if execution already ended - return without waiting
    if execution.status in Execution.END_STATES:
        return execution

    if timeout is not None:
        deadline = time.time() + timeout

    # Poll for execution status and execution logs, until execution ends
    # and we receive an event of type in WORKFLOW_END_TYPES
    offset = 0
    batch_size = 50
    event_list = []
    execution_ended = False
    while True:
        event_list = client.events.list(
            execution_id=execution.id,
            _offset=offset,
            _size=batch_size,
            include_logs=False,
            sort='@timestamp').items

        offset = offset + len(event_list)
        for event in event_list:
            logger.debug(event.get('message'))

        if timeout is not None:
            if time.time() > deadline:
                raise RuntimeError(
                    'execution of operation {0} for deployment {1} '
                    'timed out'.format(execution.workflow_id,
                                       execution.deployment_id))
            else:
                # update the remaining timeout
                timeout = deadline - time.time()

        if not execution_ended:
            execution = client.executions.get(execution.id)
            execution_ended = execution.status in Execution.END_STATES

        if execution_ended:
            break

        time.sleep(5)

    return execution


def _get_deployment_environment_creation_execution(client, deployment_id):
    """
    Get the execution id of a env preparation.

    network, security group, fip, VM creation
    """
    executions = client.executions.list(deployment_id=deployment_id)
    for execution in executions:
        if execution.workflow_id == 'create_deployment_environment':
            return execution
    raise RuntimeError('Failed to get create_deployment_environment '
                       'workflow execution.'
                       'Available executions: {0}'.format(executions))


def sig_test_format(sig_test):
    """Process the signaling result to have a short result."""
    nb_passed = 0
    nb_failures = 0
    nb_skipped = 0
    for data_test in sig_test:
        if data_test['result'] == "Passed":
            nb_passed += 1
        elif data_test['result'] == "Failed":
            nb_failures += 1
        elif data_test['result'] == "Skipped":
            nb_skipped += 1
    short_sig_test_result = {}
    short_sig_test_result['passed'] = nb_passed
    short_sig_test_result['failures'] = nb_failures
    short_sig_test_result['skipped'] = nb_skipped
    nb_test = nb_passed + nb_skipped
    return (short_sig_test_result, nb_test)


def run_blocking_ssh_command(ssh, cmd, error_msg="Unable to run this command"):
    """Command to run ssh command with the exit status."""
    stdin, stdout, stderr = ssh.exec_command(cmd)
    if stdout.channel.recv_exit_status() != 0:
        raise Exception(error_msg)