edff99cb2c9c8041d91afa384e19daea28cb8bdf
[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         extra_args = ""
153         if env.get("VMTP_HYPERVISORS"):
154             hypervisors = functest_utils.convert_ini_to_list(
155                 env.get("VMTP_HYPERVISORS"))
156             for hypervisor in hypervisors:
157                 extra_args = "{} --hypervisor {} ".format(
158                     extra_args, hypervisor)
159         cmd = ['vmtp', '-d', '--json', '{}/vmtp.json'.format(self.res_dir),
160                '-c', self.config, extra_args]
161         output = subprocess.check_output(
162             cmd, stderr=subprocess.STDOUT, env=new_env).decode("utf-8")
163         self.__logger.info("%s\n%s", " ".join(cmd), output)
164         cmd = ['vmtp_genchart', '-c', '{}/vmtp.html'.format(self.res_dir),
165                '{}/vmtp.json'.format(self.res_dir)]
166         output = subprocess.check_output(
167             cmd, stderr=subprocess.STDOUT).decode("utf-8")
168         self.__logger.info("%s\n%s", " ".join(cmd), output)
169         with open('{}/vmtp.json'.format(self.res_dir), 'r') as res_file:
170             self.details = json.load(res_file)
171
172     def run(self, **kwargs):
173         self.start_time = time.time()
174         status = testcase.TestCase.EX_RUN_ERROR
175         try:
176             assert self.cloud
177             assert super(Vmtp, self).run(**kwargs) == self.EX_OK
178             status = testcase.TestCase.EX_RUN_ERROR
179             if self.orig_cloud.get_role("admin"):
180                 role_name = "admin"
181             elif self.orig_cloud.get_role("Admin"):
182                 role_name = "Admin"
183             else:
184                 raise Exception("Cannot detect neither admin nor Admin")
185             self.orig_cloud.grant_role(
186                 role_name, user=self.project.user.id,
187                 project=self.project.project.id,
188                 domain=self.project.domain.id)
189             self.generate_keys()
190             self.write_config()
191             self.run_vmtp()
192             self.result = 100
193             status = testcase.TestCase.EX_OK
194         except subprocess.CalledProcessError as cpe:
195             self.__logger.error(
196                 "Exception when calling %s\n%s", cpe.cmd,
197                 cpe.output.decode("utf-8"))
198             self.result = 0
199         except Exception:  # pylint: disable=broad-except
200             self.__logger.exception("Cannot run vmtp")
201             self.result = 0
202         self.stop_time = time.time()
203         return status
204
205     def clean(self):
206         try:
207             assert self.cloud
208             super(Vmtp, self).clean()
209             os.remove(self.privkey_filename)
210             os.remove(self.pubkey_filename)
211             self.cloud.delete_network("pns-internal-net_{}".format(self.guid))
212             self.cloud.delete_network("pns-internal-net2_{}".format(self.guid))
213         except Exception:  # pylint: disable=broad-except
214             pass