3 # Copyright (c) 2018 Orange and others.
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
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:
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,
18 - VM to VM different network using floating IP and NAT (same as floating IP
19 inter-tenant L3, flow #3)
21 .. _VMTP: http://vmtp.readthedocs.io/en/latest/
32 from xtesting.core import testcase
34 from functest.core import singlevm
35 from functest.utils import env
36 from functest.utils import functest_utils
39 class Vmtp(singlevm.VmReady2):
40 """Class to run Vmtp_ as an OPNFV Functest testcase
42 .. _Vmtp: http://vmtp.readthedocs.io/en/latest/
44 # pylint: disable=too-many-instance-attributes
46 __logger = logging.getLogger(__name__)
48 filename = ('/home/opnfv/functest/images/'
49 'ubuntu-14.04-server-cloudimg-amd64-disk1.img')
53 create_server_timeout = 300
54 ssh_retry_timeout = 240
56 def __init__(self, **kwargs):
57 if "case_name" not in kwargs:
58 kwargs["case_name"] = 'vmtp'
59 super().__init__(**kwargs)
60 self.config = "{}/vmtp.conf".format(self.res_dir)
61 (_, self.privkey_filename) = tempfile.mkstemp()
62 (_, self.pubkey_filename) = tempfile.mkstemp()
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
70 def create_network_resources(self):
73 It creates a router which gateway is the external network detected.
75 Raises: expection on error
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)
84 def generate_keys(self):
87 Raises: Exception on error
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)
100 def write_config(self):
103 Raises: Exception on error
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(
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))
131 # pylint: disable=unexpected-keyword-arg
132 """Run Vmtp and generate charts
134 Raises: Exception on error
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"])
148 del new_env['OS_TENANT_NAME']
149 del new_env['OS_TENANT_ID']
150 except Exception: # pylint: disable=broad-except
152 cmd = ['vmtp', '-d', '--json', '{}/vmtp.json'.format(self.res_dir),
154 if env.get("VMTP_HYPERVISORS"):
155 hypervisors = functest_utils.convert_ini_to_list(
156 env.get("VMTP_HYPERVISORS"))
157 for hypervisor in hypervisors:
158 cmd.extend(["--hypervisor", hypervisor])
159 self.__logger.debug("cmd: %s", cmd)
160 output = subprocess.check_output(
161 cmd, stderr=subprocess.STDOUT, env=new_env).decode("utf-8")
162 self.__logger.info("%s\n%s", " ".join(cmd), output)
163 cmd = ['vmtp_genchart', '-c', '{}/vmtp.html'.format(self.res_dir),
164 '{}/vmtp.json'.format(self.res_dir)]
165 output = subprocess.check_output(
166 cmd, stderr=subprocess.STDOUT).decode("utf-8")
167 self.__logger.info("%s\n%s", " ".join(cmd), output)
168 with open('{}/vmtp.json'.format(self.res_dir), 'r') as res_file:
169 self.details = json.load(res_file)
171 def run(self, **kwargs):
172 self.start_time = time.time()
173 status = testcase.TestCase.EX_RUN_ERROR
176 assert super().run(**kwargs) == self.EX_OK
177 status = testcase.TestCase.EX_RUN_ERROR
178 if self.orig_cloud.get_role("admin"):
180 elif self.orig_cloud.get_role("Admin"):
183 raise Exception("Cannot detect neither admin nor Admin")
184 self.orig_cloud.grant_role(
185 role_name, user=self.project.user.id,
186 project=self.project.project.id,
187 domain=self.project.domain.id)
192 status = testcase.TestCase.EX_OK
193 except subprocess.CalledProcessError as cpe:
195 "Exception when calling %s\n%s", cpe.cmd,
196 cpe.output.decode("utf-8"))
198 except Exception: # pylint: disable=broad-except
199 self.__logger.exception("Cannot run vmtp")
201 self.stop_time = time.time()
208 os.remove(self.privkey_filename)
209 os.remove(self.pubkey_filename)
210 self.cloud.delete_network("pns-internal-net_{}".format(self.guid))
211 self.cloud.delete_network("pns-internal-net2_{}".format(self.guid))
212 except Exception: # pylint: disable=broad-except