"""Ease deploying a single VM reachable via ssh
-It offers a simple way to create all tenant network ressources + a VM for
+It offers a simple way to create all tenant network resources + a VM for
advanced testcases (e.g. deploying an orchestrator).
"""
import logging
+import re
import tempfile
import time
__logger = logging.getLogger(__name__)
filename = '/home/opnfv/functest/images/cirros-0.4.0-x86_64-disk.img'
+ image_format = 'qcow2'
+ extra_properties = {}
+ filename_alt = filename
+ image_alt_format = image_format
+ extra_alt_properties = extra_properties
visibility = 'private'
- extra_properties = None
flavor_ram = 512
flavor_vcpus = 1
flavor_disk = 1
+ flavor_extra_specs = {}
flavor_alt_ram = 1024
flavor_alt_vcpus = 1
flavor_alt_disk = 1
-
- image_format = 'qcow2'
+ flavor_alt_extra_specs = flavor_extra_specs
+ create_server_timeout = 180
def __init__(self, **kwargs):
if "case_name" not in kwargs:
kwargs["case_name"] = 'vmready1'
super(VmReady1, self).__init__(**kwargs)
- self.orig_cloud = self.cloud
self.image = None
self.flavor = None
Raises: expection on error
"""
assert self.cloud
+ extra_properties = self.extra_properties.copy()
+ extra_properties.update(
+ getattr(config.CONF, '{}_extra_properties'.format(
+ self.case_name), {}))
image = self.cloud.create_image(
name if name else '{}-img_{}'.format(self.case_name, self.guid),
filename=getattr(
config.CONF, '{}_image'.format(self.case_name),
self.filename),
- meta=getattr(
- config.CONF, '{}_extra_properties'.format(self.case_name),
- self.extra_properties),
+ meta=extra_properties,
disk_format=getattr(
config.CONF, '{}_image_format'.format(self.case_name),
self.image_format),
visibility=getattr(
config.CONF, '{}_visibility'.format(self.case_name),
- self.visibility))
+ self.visibility),
+ wait=True)
+ self.__logger.debug("image: %s", image)
+ return image
+
+ def publish_image_alt(self, name=None):
+ """Publish alternative image
+
+ It allows publishing multiple images for the child testcases. It forces
+ the same configuration for all subtestcases.
+
+ Returns: image
+
+ Raises: expection on error
+ """
+ assert self.cloud
+ extra_alt_properties = self.extra_alt_properties.copy()
+ extra_alt_properties.update(
+ getattr(config.CONF, '{}_extra_alt_properties'.format(
+ self.case_name), {}))
+ image = self.cloud.create_image(
+ name if name else '{}-img_alt_{}'.format(
+ self.case_name, self.guid),
+ filename=getattr(
+ config.CONF, '{}_image_alt'.format(self.case_name),
+ self.filename_alt),
+ meta=extra_alt_properties,
+ disk_format=getattr(
+ config.CONF, '{}_image_alt_format'.format(self.case_name),
+ self.image_format),
+ visibility=getattr(
+ config.CONF, '{}_visibility'.format(self.case_name),
+ self.visibility),
+ wait=True)
self.__logger.debug("image: %s", image)
return image
getattr(config.CONF, '{}_flavor_disk'.format(self.case_name),
self.flavor_disk))
self.__logger.debug("flavor: %s", flavor)
- self.orig_cloud.set_flavor_specs(
- flavor.id, getattr(config.CONF, 'flavor_extra_specs', {}))
+ flavor_extra_specs = self.flavor_extra_specs.copy()
+ flavor_extra_specs.update(
+ getattr(config.CONF,
+ '{}_flavor_extra_specs'.format(self.case_name), {}))
+ self.orig_cloud.set_flavor_specs(flavor.id, flavor_extra_specs)
return flavor
def create_flavor_alt(self, name=None):
getattr(config.CONF, '{}_flavor_alt_disk'.format(self.case_name),
self.flavor_alt_disk))
self.__logger.debug("flavor: %s", flavor)
+ flavor_alt_extra_specs = self.flavor_alt_extra_specs.copy()
+ flavor_alt_extra_specs.update(
+ getattr(config.CONF,
+ '{}_flavor_alt_extra_specs'.format(self.case_name), {}))
self.orig_cloud.set_flavor_specs(
- flavor.id, getattr(config.CONF, 'flavor_extra_specs', {}))
+ flavor.id, flavor_alt_extra_specs)
return flavor
def boot_vm(self, name=None, **kwargs):
vm1 = self.cloud.create_server(
name if name else '{}-vm_{}'.format(self.case_name, self.guid),
image=self.image.id, flavor=self.flavor.id,
- auto_ip=False, wait=True,
- network=self.network.id,
- **kwargs)
- vm1 = self.cloud.wait_for_server(vm1, auto_ip=False)
+ auto_ip=False, network=self.network.id,
+ timeout=self.create_server_timeout, wait=True, **kwargs)
self.__logger.debug("vm: %s", vm1)
return vm1
+ def check_regex_in_console(self, name, regex=' login: ', loop=1):
+ """Wait for specific message in console
+
+ Returns: True or False on errors
+ """
+ assert self.cloud
+ for iloop in range(loop):
+ console = self.cloud.get_server_console(name)
+ self.__logger.debug("console: \n%s", console)
+ if re.search(regex, console):
+ self.__logger.debug("regex found: ''%s' in console", regex)
+ return True
+ else:
+ self.__logger.debug(
+ "try %s: cannot find regex '%s' in console",
+ iloop + 1, regex)
+ time.sleep(10)
+ self.__logger.error("cannot find regex '%s' in console", regex)
+ return False
+
def run(self, **kwargs):
"""Boot the new VM
status = testcase.TestCase.EX_RUN_ERROR
try:
assert self.cloud
- super(VmReady1, self).run(**kwargs)
+ assert super(VmReady1, self).run(
+ **kwargs) == testcase.TestCase.EX_OK
self.image = self.publish_image()
self.flavor = self.create_flavor()
self.result = 100
status = testcase.TestCase.EX_OK
except Exception: # pylint: disable=broad-except
self.__logger.exception('Cannot run %s', self.case_name)
+ self.result = 0
finally:
self.stop_time = time.time()
return status
assert self.orig_cloud
assert self.cloud
super(VmReady1, self).clean()
- self.cloud.delete_image(self.image.id)
- self.orig_cloud.delete_flavor(self.flavor.id)
+ if self.image:
+ self.cloud.delete_image(self.image.id)
+ if self.flavor:
+ self.orig_cloud.delete_flavor(self.flavor.id)
except Exception: # pylint: disable=broad-except
- self.__logger.exception("Cannot clean all ressources")
+ self.__logger.exception("Cannot clean all resources")
class VmReady2(VmReady1):
"""Deploy a single VM reachable via ssh (scenario2)
It creates new user/project before creating and configuring all tenant
- network ressources, flavors, images, etc. required by advanced testcases.
+ network resources, flavors, images, etc. required by advanced testcases.
It ensures that all testcases inheriting from SingleVm2 could work
without specific configurations (or at least read the same config data).
assert self.project
self.project.clean()
except Exception: # pylint: disable=broad-except
- self.__logger.exception("Cannot clean all ressources")
+ self.__logger.exception("Cannot clean all resources")
class SingleVm1(VmReady1):
__logger = logging.getLogger(__name__)
username = 'cirros'
- ssh_connect_timeout = 60
+ ssh_connect_timeout = 1
+ ssh_connect_loops = 6
+ create_floating_ip_timeout = 120
def __init__(self, **kwargs):
if "case_name" not in kwargs:
"""
assert vm1
fip = self.cloud.create_floating_ip(
- network=self.ext_net.id, server=vm1)
+ network=self.ext_net.id, server=vm1, wait=True,
+ timeout=self.create_floating_ip_timeout)
self.__logger.debug("floating_ip: %s", fip)
- p_console = self.cloud.get_server_console(vm1)
- self.__logger.debug("vm console: \n%s", p_console)
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.client.AutoAddPolicy())
- for loop in range(6):
+ for loop in range(self.ssh_connect_loops):
try:
+ p_console = self.cloud.get_server_console(vm1)
+ self.__logger.debug("vm console: \n%s", p_console)
ssh.connect(
fip.floating_ip_address,
username=getattr(
'{}_vm_ssh_connect_timeout'.format(self.case_name),
self.ssh_connect_timeout))
break
- except Exception: # pylint: disable=broad-except
+ except Exception as exc: # pylint: disable=broad-except
self.__logger.debug(
- "try %s: cannot connect to %s", loop + 1,
- fip.floating_ip_address)
- time.sleep(10)
+ "try %s: cannot connect to %s: %s", loop + 1,
+ fip.floating_ip_address, exc)
+ time.sleep(9)
else:
self.__logger.error(
"cannot connect to %s", fip.floating_ip_address)
Returns: echo exit codes
"""
- (_, stdout, _) = self.ssh.exec_command('echo Hello World')
+ (_, stdout, stderr) = self.ssh.exec_command('echo Hello World')
self.__logger.debug("output:\n%s", stdout.read())
+ self.__logger.debug("error:\n%s", stderr.read())
return stdout.channel.recv_exit_status()
def run(self, **kwargs):
status = testcase.TestCase.EX_RUN_ERROR
try:
assert self.cloud
- super(SingleVm1, self).run(**kwargs)
+ assert super(SingleVm1, self).run(
+ **kwargs) == testcase.TestCase.EX_OK
self.result = 0
self.prepare()
self.sshvm = self.boot_vm(
try:
assert self.orig_cloud
assert self.cloud
- self.cloud.delete_floating_ip(self.fip.id)
- self.cloud.delete_server(self.sshvm, wait=True)
- self.cloud.delete_security_group(self.sec.id)
- self.cloud.delete_keypair(self.keypair.id)
+ if self.fip:
+ self.cloud.delete_floating_ip(self.fip.id)
+ if self.sshvm:
+ self.cloud.delete_server(self.sshvm, wait=True)
+ if self.sec:
+ self.cloud.delete_security_group(self.sec.id)
+ if self.keypair:
+ self.cloud.delete_keypair(self.keypair.name)
super(SingleVm1, self).clean()
except Exception: # pylint: disable=broad-except
- self.__logger.exception("Cannot clean all ressources")
+ self.__logger.exception("Cannot clean all resources")
class SingleVm2(SingleVm1):
"""Deploy a single VM reachable via ssh (scenario2)
It creates new user/project before creating and configuring all tenant
- network ressources and vms required by advanced testcases.
+ network resources and vms required by advanced testcases.
It ensures that all testcases inheriting from SingleVm2 could work
without specific configurations (or at least read the same config data).
assert self.project
self.project.clean()
except Exception: # pylint: disable=broad-except
- self.__logger.exception("Cannot clean all ressources")
+ self.__logger.exception("Cannot clean all resources")