1686489b8c6763a78f4497dd37ea96e8dcfc3e43
[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 from functest.utils import functest_utils
37
38
39 class Vmtp(singlevm.VmReady2):
40     """Class to run Vmtp_ as an OPNFV Functest testcase
41
42     .. _Vmtp: http://vmtp.readthedocs.io/en/latest/
43     """
44     # pylint: disable=too-many-instance-attributes
45
46     __logger = logging.getLogger(__name__)
47
48     filename = ('/home/opnfv/functest/images/'
49                 'ubuntu-14.04-server-cloudimg-amd64-disk1.img')
50     flavor_ram = 2048
51     flavor_vcpus = 1
52     flavor_disk = 0
53     create_server_timeout = 300
54     ssh_retry_timeout = 240
55
56     def __init__(self, **kwargs):
57         if "case_name" not in kwargs:
58             kwargs["case_name"] = 'vmtp'
59         super(Vmtp, self).__init__(**kwargs)
60         self.config = "{}/vmtp.conf".format(self.res_dir)
61         (_, self.privkey_filename) = tempfile.mkstemp()
62         (_, self.pubkey_filename) = tempfile.mkstemp()
63
64     def check_requirements(self):
65         if self.count_hypervisors() < 2:
66             self.__logger.warning("Vmtp requires at least 2 hypervisors")
67             self.is_skipped = True
68             self.project.clean()
69
70     def create_network_resources(self):
71         """Create router
72
73         It creates a router which gateway is the external network detected.
74
75         Raises: expection on error
76         """
77         assert self.cloud
78         assert self.ext_net
79         self.router = self.cloud.create_router(
80             name='{}-router_{}'.format(self.case_name, self.guid),
81             ext_gateway_net_id=self.ext_net.id)
82         self.__logger.debug("router: %s", self.router)
83
84     def generate_keys(self):
85         """Generate Keys
86
87         Raises: Exception on error
88         """
89         assert self.cloud
90         name = "vmtp_{}".format(self.guid)
91         self.__logger.info("Creating keypair with name: '%s'", name)
92         keypair = self.cloud.create_keypair(name)
93         self.__logger.debug("keypair: %s", keypair)
94         with open(self.privkey_filename, 'w') as key_file:
95             key_file.write(keypair.private_key)
96         with open(self.pubkey_filename, 'w') as key_file:
97             key_file.write(keypair.public_key)
98         self.cloud.delete_keypair(keypair.id)
99
100     def write_config(self):
101         """Write vmtp.conf
102
103         Raises: Exception on error
104         """
105         assert self.cloud
106         if not os.path.exists(self.res_dir):
107             os.makedirs(self.res_dir)
108         cmd = ['vmtp', '-sc']
109         output = subprocess.check_output(cmd).decode("utf-8")
110         self.__logger.info("%s\n%s", " ".join(cmd), output)
111         with open(self.config, "w+") as conf:
112             vmtp_conf = yaml.full_load(output)
113             vmtp_conf["private_key_file"] = self.privkey_filename
114             vmtp_conf["public_key_file"] = self.pubkey_filename
115             vmtp_conf["image_name"] = str(self.image.name)
116             vmtp_conf["router_name"] = str(self.router.name)
117             vmtp_conf["flavor_type"] = str(self.flavor.name)
118             vmtp_conf["internal_network_name"] = [
119                 "pns-internal-net_{}".format(self.guid),
120                 "pns-internal-net2_{}".format(self.guid)]
121             vmtp_conf["vm_name_client"] = "TestClient_{}".format(self.guid)
122             vmtp_conf["vm_name_server"] = "TestServer_{}".format(self.guid)
123             vmtp_conf["security_group_name"] = "pns-security{}".format(
124                 self.guid)
125             vmtp_conf["dns_nameservers"] = [env.get('NAMESERVER')]
126             vmtp_conf["generic_retry_count"] = self.create_server_timeout // 2
127             vmtp_conf["ssh_retry_count"] = self.ssh_retry_timeout // 2
128             conf.write(yaml.dump(vmtp_conf))
129
130     def run_vmtp(self):
131         # pylint: disable=unexpected-keyword-arg
132         """Run Vmtp and generate charts
133
134         Raises: Exception on error
135         """
136         assert self.cloud
137         new_env = dict(
138             os.environ,
139             OS_USERNAME=self.project.user.name,
140             OS_PROJECT_NAME=self.project.project.name,
141             OS_PROJECT_ID=self.project.project.id,
142             OS_PROJECT_DOMAIN_NAME=self.project.domain.name,
143             OS_USER_DOMAIN_NAME=self.project.domain.name,
144             OS_PASSWORD=self.project.password)
145         if not new_env["OS_AUTH_URL"].endswith(('v3', 'v3/')):
146             new_env["OS_AUTH_URL"] = "{}/v3".format(new_env["OS_AUTH_URL"])
147         try:
148             del new_env['OS_TENANT_NAME']
149             del new_env['OS_TENANT_ID']
150         except Exception:  # pylint: disable=broad-except
151             pass
152         cmd = ['vmtp', '-d', '--json', '{}/vmtp.json'.format(self.res_dir),
153                '-c', self.config]
154         if env.get("VMTP_HYPERVISORS"):
155             hypervisors = functest_utils.convert_ini_to_list(
156                 env.get("VMTP_HYPERVISORS"))
157             for hypervisor in hypervisors:
158                 cmd.extend(["--hypervisor", hypervisor])
159         self.__logger.debug("cmd: %s", cmd)
160         output = subprocess.check_output(
161             cmd, stderr=subprocess.STDOUT, env=new_env).decode("utf-8")
162         self.__logger.info("%s\n%s", " ".join(cmd), output)
163         cmd = ['vmtp_genchart', '-c', '{}/vmtp.html'.format(self.res_dir),
164                '{}/vmtp.json'.format(self.res_dir)]
165         output = subprocess.check_output(
166             cmd, stderr=subprocess.STDOUT).decode("utf-8")
167         self.__logger.info("%s\n%s", " ".join(cmd), output)
168         with open('{}/vmtp.json'.format(self.res_dir), 'r') as res_file:
169             self.details = json.load(res_file)
170
171     def run(self, **kwargs):
172         self.start_time = time.time()
173         status = testcase.TestCase.EX_RUN_ERROR
174         try:
175             assert self.cloud
176             assert super(Vmtp, self).run(**kwargs) == self.EX_OK
177             status = testcase.TestCase.EX_RUN_ERROR
178             if self.orig_cloud.get_role("admin"):
179                 role_name = "admin"
180             elif self.orig_cloud.get_role("Admin"):
181                 role_name = "Admin"
182             else:
183                 raise Exception("Cannot detect neither admin nor Admin")
184             self.orig_cloud.grant_role(
185                 role_name, user=self.project.user.id,
186                 project=self.project.project.id,
187                 domain=self.project.domain.id)
188             self.generate_keys()
189             self.write_config()
190             self.run_vmtp()
191             self.result = 100
192             status = testcase.TestCase.EX_OK
193         except subprocess.CalledProcessError as cpe:
194             self.__logger.error(
195                 "Exception when calling %s\n%s", cpe.cmd,
196                 cpe.output.decode("utf-8"))
197             self.result = 0
198         except Exception:  # pylint: disable=broad-except
199             self.__logger.exception("Cannot run vmtp")
200             self.result = 0
201         self.stop_time = time.time()
202         return status
203
204     def clean(self):
205         try:
206             assert self.cloud
207             super(Vmtp, self).clean()
208             os.remove(self.privkey_filename)
209             os.remove(self.pubkey_filename)
210             self.cloud.delete_network("pns-internal-net_{}".format(self.guid))
211             self.cloud.delete_network("pns-internal-net2_{}".format(self.guid))
212         except Exception:  # pylint: disable=broad-except
213             pass