Decode tempest exception output (py3)
[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 len(self.orig_cloud.list_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         """Run Vmtp and generate charts
129
130         Raises: Exception on error
131         """
132         assert self.cloud
133         new_env = dict(
134             os.environ,
135             OS_USERNAME=self.project.user.name,
136             OS_PROJECT_NAME=self.project.project.name,
137             OS_PROJECT_ID=self.project.project.id,
138             OS_PASSWORD=self.project.password)
139         if not new_env["OS_AUTH_URL"].endswith(('v3', 'v3/')):
140             new_env["OS_AUTH_URL"] = "{}/v3".format(new_env["OS_AUTH_URL"])
141         try:
142             del new_env['OS_TENANT_NAME']
143             del new_env['OS_TENANT_ID']
144         except Exception:  # pylint: disable=broad-except
145             pass
146         cmd = ['vmtp', '-d', '--json', '{}/vmtp.json'.format(self.res_dir),
147                '-c', self.config]
148         output = subprocess.check_output(
149             cmd, stderr=subprocess.STDOUT, env=new_env).decode("utf-8")
150         self.__logger.info("%s\n%s", " ".join(cmd), output)
151         cmd = ['vmtp_genchart', '-c', '{}/vmtp.html'.format(self.res_dir),
152                '{}/vmtp.json'.format(self.res_dir)]
153         output = subprocess.check_output(
154             cmd, stderr=subprocess.STDOUT).decode("utf-8")
155         self.__logger.info("%s\n%s", " ".join(cmd), output)
156         with open('{}/vmtp.json'.format(self.res_dir), 'r') as res_file:
157             self.details = json.load(res_file)
158
159     def run(self, **kwargs):
160         self.start_time = time.time()
161         status = testcase.TestCase.EX_RUN_ERROR
162         try:
163             assert self.cloud
164             assert super(Vmtp, self).run(**kwargs) == self.EX_OK
165             status = testcase.TestCase.EX_RUN_ERROR
166             if self.orig_cloud.get_role("admin"):
167                 role_name = "admin"
168             elif self.orig_cloud.get_role("Admin"):
169                 role_name = "Admin"
170             else:
171                 raise Exception("Cannot detect neither admin nor Admin")
172             self.orig_cloud.grant_role(
173                 role_name, user=self.project.user.id,
174                 project=self.project.project.id,
175                 domain=self.project.domain.id)
176             self.generate_keys()
177             self.write_config()
178             self.run_vmtp()
179             self.result = 100
180             status = testcase.TestCase.EX_OK
181         except subprocess.CalledProcessError as cpe:
182             self.__logger.error(
183                 "Exception when calling %s\n%s", cpe.cmd,
184                 cpe.output.decode("utf-8"))
185             self.result = 0
186         except Exception:  # pylint: disable=broad-except
187             self.__logger.exception("Cannot run vmtp")
188             self.result = 0
189         self.stop_time = time.time()
190         return status
191
192     def clean(self):
193         try:
194             assert self.cloud
195             super(Vmtp, self).clean()
196             os.remove(self.privkey_filename)
197             os.remove(self.pubkey_filename)
198             self.cloud.delete_network("pns-internal-net_{}".format(self.guid))
199             self.cloud.delete_network("pns-internal-net2_{}".format(self.guid))
200         except Exception:  # pylint: disable=broad-except
201             pass