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'
40 visibility = 'private'
41 extra_properties = None
46 def __init__(self, **kwargs):
47 if "case_name" not in kwargs:
48 kwargs["case_name"] = 'vmready1'
49 super(VmReady1, self).__init__(**kwargs)
50 self.orig_cloud = self.cloud
54 def _publish_image(self):
56 self.image = self.cloud.create_image(
57 '{}-img_{}'.format(self.case_name, self.guid),
59 config.CONF, '{}_image'.format(self.case_name),
62 config.CONF, '{}_extra_properties'.format(self.case_name),
63 self.extra_properties),
65 config.CONF, '{}_visibility'.format(self.case_name),
67 self.__logger.debug("image: %s", self.image)
69 def _create_flavor(self):
70 assert self.orig_cloud
71 self.flavor = self.orig_cloud.create_flavor(
72 '{}-flavor_{}'.format(self.case_name, self.guid),
73 getattr(config.CONF, '{}_flavor_ram'.format(self.case_name),
75 getattr(config.CONF, '{}_flavor_vcpus'.format(self.case_name),
77 getattr(config.CONF, '{}_flavor_disk'.format(self.case_name),
79 self.__logger.debug("flavor: %s", self.flavor)
80 self.orig_cloud.set_flavor_specs(
81 self.flavor.id, getattr(config.CONF, 'flavor_extra_specs', {}))
83 def run(self, **kwargs):
86 Here are the main actions:
92 - TestCase.EX_RUN_ERROR on error
94 status = testcase.TestCase.EX_RUN_ERROR
97 super(VmReady1, self).run(**kwargs)
101 status = testcase.TestCase.EX_OK
102 except Exception: # pylint: disable=broad-except
103 self.__logger.exception('Cannot run %s', self.case_name)
105 self.stop_time = time.time()
110 assert self.orig_cloud
112 super(VmReady1, self).clean()
113 self.cloud.delete_image(self.image.id)
114 self.orig_cloud.delete_flavor(self.flavor.id)
115 except Exception: # pylint: disable=broad-except
116 self.__logger.exception("Cannot clean all ressources")
119 class VmReady2(VmReady1):
120 """Deploy a single VM reachable via ssh (scenario2)
122 It creates new user/project before creating and configuring all tenant
123 network ressources, flavors, images, etc. required by advanced testcases.
125 It ensures that all testcases inheriting from SingleVm2 could work
126 without specific configurations (or at least read the same config data).
129 __logger = logging.getLogger(__name__)
131 def __init__(self, **kwargs):
132 if "case_name" not in kwargs:
133 kwargs["case_name"] = 'vmready2'
134 super(VmReady2, self).__init__(**kwargs)
136 assert self.orig_cloud
137 self.project = tenantnetwork.NewProject(
138 self.orig_cloud, self.case_name, self.guid)
139 self.project.create()
140 self.cloud = self.project.cloud
141 except Exception: # pylint: disable=broad-except
142 self.__logger.exception("Cannot create user or project")
148 super(VmReady2, self).clean()
151 except Exception: # pylint: disable=broad-except
152 self.__logger.exception("Cannot clean all ressources")
155 class SingleVm1(VmReady1):
156 """Deploy a single VM reachable via ssh (scenario1)
158 It inherits from TenantNetwork1 which creates all network resources and
159 completes it by booting a VM attached to that network.
161 It ensures that all testcases inheriting from SingleVm1 could work
162 without specific configurations (or at least read the same config data).
164 # pylint: disable=too-many-instance-attributes
166 __logger = logging.getLogger(__name__)
168 ssh_connect_timeout = 60
170 def __init__(self, **kwargs):
171 if "case_name" not in kwargs:
172 kwargs["case_name"] = 'singlevm1'
173 super(SingleVm1, self).__init__(**kwargs)
178 self.ssh = paramiko.SSHClient()
179 (_, self.key_filename) = tempfile.mkstemp()
181 def create_sg_rules(self):
182 """Create the security group
184 It can be overriden to set other rules according to the services
187 Raises: Exception on error
190 self.sec = self.cloud.create_security_group(
191 '{}-sg_{}'.format(self.case_name, self.guid),
192 'created by OPNFV Functest ({})'.format(self.case_name))
193 self.cloud.create_security_group_rule(
194 self.sec.id, port_range_min='22', port_range_max='22',
195 protocol='tcp', direction='ingress')
196 self.cloud.create_security_group_rule(
197 self.sec.id, protocol='icmp', direction='ingress')
201 self.keypair = self.cloud.create_keypair(
202 '{}-kp_{}'.format(self.case_name, self.guid))
203 self.__logger.debug("keypair: %s", self.keypair)
204 self.__logger.debug("private_key: %s", self.keypair.private_key)
205 with open(self.key_filename, 'w') as private_key_file:
206 private_key_file.write(self.keypair.private_key)
208 self.sshvm = self.cloud.create_server(
209 '{}-vm_{}'.format(self.case_name, self.guid),
210 image=self.image.id, flavor=self.flavor.id,
211 key_name=self.keypair.id,
212 auto_ip=False, wait=True,
213 network=self.network.id,
214 security_groups=[self.sec.id])
215 self.__logger.debug("vm: %s", self.sshvm)
216 self.fip = self.cloud.create_floating_ip(
217 network=self.ext_net.id, server=self.sshvm)
218 self.__logger.debug("floating_ip: %s", self.fip)
219 self.sshvm = self.cloud.wait_for_server(self.sshvm, auto_ip=False)
223 p_console = self.cloud.get_server_console(self.sshvm.id)
224 self.__logger.debug("vm console: \n%s", p_console)
225 self.ssh.set_missing_host_key_policy(paramiko.client.AutoAddPolicy())
226 for loop in range(6):
229 self.sshvm.public_v4,
232 '{}_image_user'.format(self.case_name), self.username),
233 key_filename=self.key_filename,
236 '{}_vm_ssh_connect_timeout'.format(self.case_name),
237 self.ssh_connect_timeout))
239 except Exception: # pylint: disable=broad-except
241 "try %s: cannot connect to %s", loop + 1,
242 self.sshvm.public_v4)
245 self.__logger.error("cannot connect to %s", self.sshvm.public_v4)
250 """Say hello world via ssh
252 It can be overriden to execute any command.
254 Returns: echo exit codes
256 (_, stdout, _) = self.ssh.exec_command('echo Hello World')
257 self.__logger.debug("output:\n%s", stdout.read())
258 return stdout.channel.recv_exit_status()
260 def run(self, **kwargs):
263 Here are the main actions:
266 - create the security group
267 - execute the right command over ssh
271 - TestCase.EX_RUN_ERROR on error
273 status = testcase.TestCase.EX_RUN_ERROR
276 super(SingleVm1, self).run(**kwargs)
278 self.create_sg_rules()
280 assert self._connect()
281 if not self.execute():
283 status = testcase.TestCase.EX_OK
284 except Exception: # pylint: disable=broad-except
285 self.__logger.exception('Cannot run %s', self.case_name)
287 self.stop_time = time.time()
292 assert self.orig_cloud
294 self.cloud.delete_floating_ip(self.fip.id)
295 self.cloud.delete_server(self.sshvm, wait=True)
296 self.cloud.delete_security_group(self.sec.id)
297 self.cloud.delete_keypair(self.keypair.id)
298 super(SingleVm1, self).clean()
299 except Exception: # pylint: disable=broad-except
300 self.__logger.exception("Cannot clean all ressources")
303 class SingleVm2(SingleVm1):
304 """Deploy a single VM reachable via ssh (scenario2)
306 It creates new user/project before creating and configuring all tenant
307 network ressources and vms required by advanced testcases.
309 It ensures that all testcases inheriting from SingleVm2 could work
310 without specific configurations (or at least read the same config data).
313 __logger = logging.getLogger(__name__)
315 def __init__(self, **kwargs):
316 if "case_name" not in kwargs:
317 kwargs["case_name"] = 'singlevm2'
318 super(SingleVm2, self).__init__(**kwargs)
320 assert self.orig_cloud
321 self.project = tenantnetwork.NewProject(
322 self.orig_cloud, self.case_name, self.guid)
323 self.project.create()
324 self.cloud = self.project.cloud
325 except Exception: # pylint: disable=broad-except
326 self.__logger.exception("Cannot create user or project")
332 super(SingleVm2, self).clean()
335 except Exception: # pylint: disable=broad-except
336 self.__logger.exception("Cannot clean all ressources")