Merge "Count all active hypervisors"
[functest.git] / functest / opnfv_tests / openstack / vmtp / vmtp.py
1 #!/usr/bin/env python
2
3 # Copyright (c) 2018 Orange and others.
4 #
5 # All rights reserved. This program and the accompanying materials
6 # are made available under the terms of the Apache License, Version 2.0
7 # which accompanies this distribution, and is available at
8 # http://www.apache.org/licenses/LICENSE-2.0
9
10 """
11 VMTP_ is a small python application that will automatically perform ping
12 connectivity, round trip time measurement (latency) and TCP/UDP throughput
13 measurement for the following East/West flows on any OpenStack deployment:
14
15 - VM to VM same network (private fixed IP, flow #1)
16 - VM to VM different network using fixed IP (same as intra-tenant L3 fixed IP,
17   flow #2)
18 - VM to VM different network using floating IP and NAT (same as floating IP
19   inter-tenant L3, flow #3)
20
21 .. _VMTP: http://vmtp.readthedocs.io/en/latest/
22 """
23
24 import json
25 import logging
26 import os
27 import subprocess
28 import tempfile
29 import time
30 import yaml
31
32 from xtesting.core import testcase
33
34 from functest.core import singlevm
35 from functest.utils import env
36
37
38 class Vmtp(singlevm.VmReady2):
39     """Class to run Vmtp_ as an OPNFV Functest testcase
40
41     .. _Vmtp: http://vmtp.readthedocs.io/en/latest/
42     """
43     # pylint: disable=too-many-instance-attributes
44
45     __logger = logging.getLogger(__name__)
46
47     filename = ('/home/opnfv/functest/images/'
48                 'ubuntu-14.04-server-cloudimg-amd64-disk1.img')
49     flavor_ram = 2048
50     flavor_vcpus = 1
51     flavor_disk = 0
52     create_server_timeout = 300
53
54     def __init__(self, **kwargs):
55         if "case_name" not in kwargs:
56             kwargs["case_name"] = 'vmtp'
57         super(Vmtp, self).__init__(**kwargs)
58         self.config = "{}/vmtp.conf".format(self.res_dir)
59         (_, self.privkey_filename) = tempfile.mkstemp()
60         (_, self.pubkey_filename) = tempfile.mkstemp()
61
62     def check_requirements(self):
63         if self.count_active_hypervisors() < 2:
64             self.__logger.warning("Vmtp requires at least 2 hypervisors")
65             self.is_skipped = True
66             self.project.clean()
67
68     def create_network_resources(self):
69         """Create router
70
71         It creates a router which gateway is the external network detected.
72
73         Raises: expection on error
74         """
75         assert self.cloud
76         assert self.ext_net
77         self.router = self.cloud.create_router(
78             name='{}-router_{}'.format(self.case_name, self.guid),
79             ext_gateway_net_id=self.ext_net.id)
80         self.__logger.debug("router: %s", self.router)
81
82     def generate_keys(self):
83         """Generate Keys
84
85         Raises: Exception on error
86         """
87         assert self.cloud
88         name = "vmtp_{}".format(self.guid)
89         self.__logger.info("Creating keypair with name: '%s'", name)
90         keypair = self.cloud.create_keypair(name)
91         self.__logger.debug("keypair: %s", keypair)
92         with open(self.privkey_filename, 'w') as key_file:
93             key_file.write(keypair.private_key)
94         with open(self.pubkey_filename, 'w') as key_file:
95             key_file.write(keypair.public_key)
96         self.cloud.delete_keypair(keypair.id)
97
98     def write_config(self):
99         """Write vmtp.conf
100
101         Raises: Exception on error
102         """
103         assert self.cloud
104         if not os.path.exists(self.res_dir):
105             os.makedirs(self.res_dir)
106         cmd = ['vmtp', '-sc']
107         output = subprocess.check_output(cmd).decode("utf-8")
108         self.__logger.info("%s\n%s", " ".join(cmd), output)
109         with open(self.config, "w+") as conf:
110             vmtp_conf = yaml.full_load(output)
111             vmtp_conf["private_key_file"] = self.privkey_filename
112             vmtp_conf["public_key_file"] = self.pubkey_filename
113             vmtp_conf["image_name"] = str(self.image.name)
114             vmtp_conf["router_name"] = str(self.router.name)
115             vmtp_conf["flavor_type"] = str(self.flavor.name)
116             vmtp_conf["internal_network_name"] = [
117                 "pns-internal-net_{}".format(self.guid),
118                 "pns-internal-net2_{}".format(self.guid)]
119             vmtp_conf["vm_name_client"] = "TestClient_{}".format(self.guid)
120             vmtp_conf["vm_name_server"] = "TestServer_{}".format(self.guid)
121             vmtp_conf["security_group_name"] = "pns-security{}".format(
122                 self.guid)
123             vmtp_conf["dns_nameservers"] = [env.get('NAMESERVER')]
124             vmtp_conf["generic_retry_count"] = self.create_server_timeout // 2
125             conf.write(yaml.dump(vmtp_conf))
126
127     def run_vmtp(self):
128         # pylint: disable=unexpected-keyword-arg
129         """Run Vmtp and generate charts
130
131         Raises: Exception on error
132         """
133         assert self.cloud
134         new_env = dict(
135             os.environ,
136             OS_USERNAME=self.project.user.name,
137             OS_PROJECT_NAME=self.project.project.name,
138             OS_PROJECT_ID=self.project.project.id,
139             OS_PROJECT_DOMAIN_NAME=self.project.domain.name,
140             OS_USER_DOMAIN_NAME=self.project.domain.name,
141             OS_PASSWORD=self.project.password)
142         if not new_env["OS_AUTH_URL"].endswith(('v3', 'v3/')):
143             new_env["OS_AUTH_URL"] = "{}/v3".format(new_env["OS_AUTH_URL"])
144         try:
145             del new_env['OS_TENANT_NAME']
146             del new_env['OS_TENANT_ID']
147         except Exception:  # pylint: disable=broad-except
148             pass
149         cmd = ['vmtp', '-d', '--json', '{}/vmtp.json'.format(self.res_dir),
150                '-c', self.config]
151         output = subprocess.check_output(
152             cmd, stderr=subprocess.STDOUT, env=new_env).decode("utf-8")
153         self.__logger.info("%s\n%s", " ".join(cmd), output)
154         cmd = ['vmtp_genchart', '-c', '{}/vmtp.html'.format(self.res_dir),
155                '{}/vmtp.json'.format(self.res_dir)]
156         output = subprocess.check_output(
157             cmd, stderr=subprocess.STDOUT).decode("utf-8")
158         self.__logger.info("%s\n%s", " ".join(cmd), output)
159         with open('{}/vmtp.json'.format(self.res_dir), 'r') as res_file:
160             self.details = json.load(res_file)
161
162     def run(self, **kwargs):
163         self.start_time = time.time()
164         status = testcase.TestCase.EX_RUN_ERROR
165         try:
166             assert self.cloud
167             assert super(Vmtp, self).run(**kwargs) == self.EX_OK
168             status = testcase.TestCase.EX_RUN_ERROR
169             if self.orig_cloud.get_role("admin"):
170                 role_name = "admin"
171             elif self.orig_cloud.get_role("Admin"):
172                 role_name = "Admin"
173             else:
174                 raise Exception("Cannot detect neither admin nor Admin")
175             self.orig_cloud.grant_role(
176                 role_name, user=self.project.user.id,
177                 project=self.project.project.id,
178                 domain=self.project.domain.id)
179             self.generate_keys()
180             self.write_config()
181             self.run_vmtp()
182             self.result = 100
183             status = testcase.TestCase.EX_OK
184         except subprocess.CalledProcessError as cpe:
185             self.__logger.error(
186                 "Exception when calling %s\n%s", cpe.cmd,
187                 cpe.output.decode("utf-8"))
188             self.result = 0
189         except Exception:  # pylint: disable=broad-except
190             self.__logger.exception("Cannot run vmtp")
191             self.result = 0
192         self.stop_time = time.time()
193         return status
194
195     def clean(self):
196         try:
197             assert self.cloud
198             super(Vmtp, self).clean()
199             os.remove(self.privkey_filename)
200             os.remove(self.pubkey_filename)
201             self.cloud.delete_network("pns-internal-net_{}".format(self.guid))
202             self.cloud.delete_network("pns-internal-net2_{}".format(self.guid))
203         except Exception:  # pylint: disable=broad-except
204             pass