Remove python warnings (yaml.load)
[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)
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)
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(cmd, stderr=subprocess.STDOUT)
154         self.__logger.info("%s\n%s", " ".join(cmd), output)
155         with open('{}/vmtp.json'.format(self.res_dir), 'r') as res_file:
156             self.details = json.load(res_file)
157
158     def run(self, **kwargs):
159         self.start_time = time.time()
160         status = testcase.TestCase.EX_RUN_ERROR
161         try:
162             assert self.cloud
163             assert super(Vmtp, self).run(**kwargs) == self.EX_OK
164             status = testcase.TestCase.EX_RUN_ERROR
165             if self.orig_cloud.get_role("admin"):
166                 role_name = "admin"
167             elif self.orig_cloud.get_role("Admin"):
168                 role_name = "Admin"
169             else:
170                 raise Exception("Cannot detect neither admin nor Admin")
171             self.orig_cloud.grant_role(
172                 role_name, user=self.project.user.id,
173                 project=self.project.project.id,
174                 domain=self.project.domain.id)
175             self.generate_keys()
176             self.write_config()
177             self.run_vmtp()
178             self.result = 100
179             status = testcase.TestCase.EX_OK
180         except subprocess.CalledProcessError as cpe:
181             self.__logger.error(
182                 "Exception when calling %s\n%s", cpe.cmd, cpe.output)
183             self.result = 0
184         except Exception:  # pylint: disable=broad-except
185             self.__logger.exception("Cannot run vmtp")
186             self.result = 0
187         self.stop_time = time.time()
188         return status
189
190     def clean(self):
191         try:
192             assert self.cloud
193             super(Vmtp, self).clean()
194             os.remove(self.privkey_filename)
195             os.remove(self.pubkey_filename)
196             self.cloud.delete_network("pns-internal-net_{}".format(self.guid))
197             self.cloud.delete_network("pns-internal-net2_{}".format(self.guid))
198         except Exception:  # pylint: disable=broad-except
199             pass