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
10 """Ease deploying a single VM reachable via ssh
12 It offers a simple way to create all tenant network ressources + a VM for
13 advanced testcases (e.g. deploying an orchestrator).
21 from xtesting.core import testcase
23 from functest.core import tenantnetwork
24 from functest.utils import config
27 class VmReady1(tenantnetwork.TenantNetwork1):
28 """Deploy a single VM reachable via ssh (scenario1)
30 It inherits from TenantNetwork1 which creates all network resources and
31 prepares a future VM attached to that network.
33 It ensures that all testcases inheriting from SingleVm1 could work
34 without specific configurations (or at least read the same config data).
36 # pylint: disable=too-many-instance-attributes
38 __logger = logging.getLogger(__name__)
39 filename = '/home/opnfv/functest/images/cirros-0.4.0-x86_64-disk.img'
44 def __init__(self, **kwargs):
45 if "case_name" not in kwargs:
46 kwargs["case_name"] = 'vmready1'
47 super(VmReady1, self).__init__(**kwargs)
48 self.orig_cloud = self.cloud
52 def _publish_image(self):
55 config.CONF, '{}_extra_properties'.format(self.case_name), None)
56 self.image = self.cloud.create_image(
57 '{}-img_{}'.format(self.case_name, self.guid),
59 config.CONF, '{}_image'.format(self.case_name),
62 self.__logger.debug("image: %s", self.image)
64 def _create_flavor(self):
65 assert self.orig_cloud
66 self.flavor = self.orig_cloud.create_flavor(
67 '{}-flavor_{}'.format(self.case_name, self.guid),
68 getattr(config.CONF, '{}_flavor_ram'.format(self.case_name),
70 getattr(config.CONF, '{}_flavor_vcpus'.format(self.case_name),
72 getattr(config.CONF, '{}_flavor_disk'.format(self.case_name),
74 self.__logger.debug("flavor: %s", self.flavor)
75 self.orig_cloud.set_flavor_specs(
76 self.flavor.id, getattr(config.CONF, 'flavor_extra_specs', {}))
78 def run(self, **kwargs):
81 Here are the main actions:
87 - TestCase.EX_RUN_ERROR on error
89 status = testcase.TestCase.EX_RUN_ERROR
92 super(VmReady1, self).run(**kwargs)
96 status = testcase.TestCase.EX_OK
97 except Exception: # pylint: disable=broad-except
98 self.__logger.exception('Cannot run %s', self.case_name)
100 self.stop_time = time.time()
105 assert self.orig_cloud
107 self.cloud.delete_image(self.image)
108 self.orig_cloud.delete_flavor(self.flavor.id)
109 self.cloud.delete_image(self.image)
110 except Exception: # pylint: disable=broad-except
114 class VmReady2(VmReady1):
115 """Deploy a single VM reachable via ssh (scenario2)
117 It creates new user/project before creating and configuring all tenant
118 network ressources, flavors, images, etc. required by advanced testcases.
120 It ensures that all testcases inheriting from SingleVm2 could work
121 without specific configurations (or at least read the same config data).
124 __logger = logging.getLogger(__name__)
126 def __init__(self, **kwargs):
127 if "case_name" not in kwargs:
128 kwargs["case_name"] = 'vmready2'
129 super(VmReady2, self).__init__(**kwargs)
131 assert self.orig_cloud
132 self.project = tenantnetwork.NewProject(
133 self.orig_cloud, self.case_name, self.guid)
134 self.project.create()
135 self.cloud = self.project.cloud
136 except Exception: # pylint: disable=broad-except
137 self.__logger.exception("Cannot create user or project")
143 super(VmReady2, self).clean()
146 except Exception: # pylint: disable=broad-except
147 self.__logger.exception("cannot clean all ressources")
150 class SingleVm1(VmReady1):
151 """Deploy a single VM reachable via ssh (scenario1)
153 It inherits from TenantNetwork1 which creates all network resources and
154 completes it by booting a VM attached to that network.
156 It ensures that all testcases inheriting from SingleVm1 could work
157 without specific configurations (or at least read the same config data).
159 # pylint: disable=too-many-instance-attributes
161 __logger = logging.getLogger(__name__)
163 ssh_connect_timeout = 60
165 def __init__(self, **kwargs):
166 if "case_name" not in kwargs:
167 kwargs["case_name"] = 'singlevm1'
168 super(SingleVm1, self).__init__(**kwargs)
173 self.ssh = paramiko.SSHClient()
174 (_, self.key_filename) = tempfile.mkstemp()
176 def create_sg_rules(self):
177 """Create the security group
179 It can be overriden to set other rules according to the services
182 Raises: Exception on error
185 self.sec = self.cloud.create_security_group(
186 '{}-sg_{}'.format(self.case_name, self.guid),
187 'created by OPNFV Functest ({})'.format(self.case_name))
188 self.cloud.create_security_group_rule(
189 self.sec.id, port_range_min='22', port_range_max='22',
190 protocol='tcp', direction='ingress')
191 self.cloud.create_security_group_rule(
192 self.sec.id, protocol='icmp', direction='ingress')
196 self.keypair = self.cloud.create_keypair(
197 '{}-kp_{}'.format(self.case_name, self.guid))
198 self.__logger.debug("keypair: %s", self.keypair)
199 self.__logger.debug("private_key: %s", self.keypair.private_key)
200 with open(self.key_filename, 'w') as private_key_file:
201 private_key_file.write(self.keypair.private_key)
203 self.sshvm = self.cloud.create_server(
204 '{}-vm_{}'.format(self.case_name, self.guid),
205 image=self.image.id, flavor=self.flavor.id,
206 key_name=self.keypair.id,
207 auto_ip=False, wait=True,
208 network=self.network.id,
209 security_groups=[self.sec.id])
210 self.__logger.debug("vm: %s", self.sshvm)
211 self.fip = self.cloud.create_floating_ip(
212 network=self.ext_net.id, server=self.sshvm)
213 self.__logger.debug("floating_ip: %s", self.fip)
214 self.sshvm = self.cloud.wait_for_server(self.sshvm, auto_ip=False)
218 p_console = self.cloud.get_server_console(self.sshvm.id)
219 self.__logger.debug("vm console: \n%s", p_console)
220 self.ssh.set_missing_host_key_policy(paramiko.client.AutoAddPolicy())
221 for loop in range(6):
224 self.sshvm.public_v4,
227 '{}_image_user'.format(self.case_name), self.username),
228 key_filename=self.key_filename,
231 '{}_vm_ssh_connect_timeout'.format(self.case_name),
232 self.ssh_connect_timeout))
234 except Exception: # pylint: disable=broad-except
236 "try %s: cannot connect to %s", loop + 1,
237 self.sshvm.public_v4)
240 self.__logger.error("cannot connect to %s", self.sshvm.public_v4)
245 """Say hello world via ssh
247 It can be overriden to execute any command.
249 Returns: echo exit codes
251 (_, stdout, _) = self.ssh.exec_command('echo Hello World')
252 self.__logger.info("output:\n%s", stdout.read())
253 return stdout.channel.recv_exit_status()
255 def run(self, **kwargs):
258 Here are the main actions:
261 - create the security group
262 - execute the right command over ssh
266 - TestCase.EX_RUN_ERROR on error
268 status = testcase.TestCase.EX_RUN_ERROR
271 super(SingleVm1, self).run(**kwargs)
273 self.create_sg_rules()
275 assert self._connect()
276 if not self.execute():
278 status = testcase.TestCase.EX_OK
279 except Exception: # pylint: disable=broad-except
280 self.__logger.exception('Cannot run %s', self.case_name)
282 self.stop_time = time.time()
287 assert self.orig_cloud
289 self.cloud.delete_server(self.sshvm, wait=True)
290 self.cloud.delete_security_group(self.sec.id)
291 self.cloud.delete_image(self.image)
292 self.orig_cloud.delete_flavor(self.flavor.id)
293 self.cloud.delete_keypair(self.keypair.id)
294 self.cloud.delete_floating_ip(self.fip.id)
295 self.cloud.delete_image(self.image)
296 except Exception: # pylint: disable=broad-except
300 class SingleVm2(SingleVm1):
301 """Deploy a single VM reachable via ssh (scenario2)
303 It creates new user/project before creating and configuring all tenant
304 network ressources and vms required by advanced testcases.
306 It ensures that all testcases inheriting from SingleVm2 could work
307 without specific configurations (or at least read the same config data).
310 __logger = logging.getLogger(__name__)
312 def __init__(self, **kwargs):
313 if "case_name" not in kwargs:
314 kwargs["case_name"] = 'singlevm2'
315 super(SingleVm2, self).__init__(**kwargs)
317 assert self.orig_cloud
318 self.project = tenantnetwork.NewProject(
319 self.orig_cloud, self.case_name, self.guid)
320 self.project.create()
321 self.cloud = self.project.cloud
322 except Exception: # pylint: disable=broad-except
323 self.__logger.exception("Cannot create user or project")
329 super(SingleVm2, self).clean()
332 except Exception: # pylint: disable=broad-except
333 self.__logger.exception("cannot clean all ressources")