6bad9aec2969f9eab1ec997fedb58d71957893a3
[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 import six
33 from xtesting.core import testcase
34
35 from functest.core import singlevm
36 from functest.utils import env
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
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 len(self.orig_cloud.list_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)
109         self.__logger.info("%s\n%s", " ".join(cmd), output)
110         with open(self.config, "w+") as conf:
111             vmtp_conf = yaml.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             conf.write(yaml.dump(vmtp_conf))
127
128     def run_vmtp(self):
129         """Run Vmtp and generate charts
130
131         Raises: Exception on error
132         """
133         assert self.cloud
134         new_env = dict(
135             os.environ,
136             OS_USERNAME=self.project.user.name,
137             OS_PROJECT_NAME=self.project.project.name,
138             OS_PROJECT_ID=self.project.project.id,
139             OS_PASSWORD=self.project.password)
140         if not new_env["OS_AUTH_URL"].endswith(('v3', 'v3/')):
141             new_env["OS_AUTH_URL"] = six.moves.urllib.parse.urljoin(
142                 new_env["OS_AUTH_URL"], 'v3')
143         try:
144             del new_env['OS_TENANT_NAME']
145             del new_env['OS_TENANT_ID']
146         except Exception:  # pylint: disable=broad-except
147             pass
148         cmd = ['vmtp', '-d', '--json', '{}/vmtp.json'.format(self.res_dir),
149                '-c', self.config]
150         output = subprocess.check_output(
151             cmd, stderr=subprocess.STDOUT, env=new_env)
152         self.__logger.info("%s\n%s", " ".join(cmd), output)
153         cmd = ['vmtp_genchart', '-c', '{}/vmtp.html'.format(self.res_dir),
154                '{}/vmtp.json'.format(self.res_dir)]
155         output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
156         self.__logger.info("%s\n%s", " ".join(cmd), output)
157         with open('{}/vmtp.json'.format(self.res_dir), 'r') as res_file:
158             self.details = json.load(res_file)
159
160     def run(self, **kwargs):
161         self.start_time = time.time()
162         status = testcase.TestCase.EX_RUN_ERROR
163         try:
164             assert self.cloud
165             assert super(Vmtp, self).run(**kwargs) == self.EX_OK
166             status = testcase.TestCase.EX_RUN_ERROR
167             if self.orig_cloud.get_role("admin"):
168                 role_name = "admin"
169             elif self.orig_cloud.get_role("Admin"):
170                 role_name = "Admin"
171             else:
172                 raise Exception("Cannot detect neither admin nor Admin")
173             self.orig_cloud.grant_role(
174                 role_name, user=self.project.user.id,
175                 project=self.project.project.id,
176                 domain=self.project.domain.id)
177             self.generate_keys()
178             self.write_config()
179             self.run_vmtp()
180             self.result = 100
181             status = testcase.TestCase.EX_OK
182         except subprocess.CalledProcessError as cpe:
183             self.__logger.error(
184                 "Exception when calling %s\n%s", cpe.cmd, cpe.output)
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