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