Source code for ovirtlago.virt

#
# Copyright 2015 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
#
# Refer to the README and COPYING files for full details of the license
#
import os
import time
import warnings

import lago
import lago.vm
from lago.config import config as lago_config

import ovirtsdk.api
from ovirtsdk.infrastructure.errors import (RequestError, ConnectionError)
try:
    import ovirtsdk4 as sdk4
    API_V4 = True
except ImportError:
    sdk4 = None
    API_V4 = False

from . import (
    constants,
    testlib,
)


[docs]class OvirtVirtEnv(lago.virt.VirtEnv): def __init__(self, prefix, vm_specs, net_spec): self._engine_vm = None self._host_vms = [] self._ovirt_cpu_family = None super(OvirtVirtEnv, self).__init__(prefix, vm_specs, net_spec)
[docs] def _create_vm(self, vm_spec): metadata = vm_spec.get('metadata', {}) role = metadata.get('ovirt-role', None) if role: warnings.warn( 'ovirt-role metadata entry will be soon deprecated, instead ' 'you should use the vm-provider entry in the domain ' 'definition and set it no one of: ovirt-node, ovirt-engine, ' 'ovirt-host' ) provider_name = 'ovirt-' + role else: provider_name = vm_spec.get( 'vm-type', lago_config.get('default_vm_provider', 'default'), ) if provider_name == 'ovirt-engine': if self._engine_vm is not None: raise RuntimeError('Engine VM already exists') vm_spec['vm-type'] = provider_name self._engine_vm = super(OvirtVirtEnv, self)._create_vm(vm_spec) return self._engine_vm elif provider_name in ('ovirt-host', 'ovirt-node'): vm_spec['vm-type'] = provider_name self._host_vms.append( super(OvirtVirtEnv, self)._create_vm(vm_spec) ) return self._host_vms[-1] else: return super(OvirtVirtEnv, self)._create_vm(vm_spec)
[docs] def engine_vm(self): return self._engine_vm
[docs] def host_vms(self): return self._host_vms[:]
[docs] def get_ovirt_cpu_family(self): return super(OvirtVirtEnv, self).get_compatible_cpu_and_family()[1]
# TODO : solve the problem of ssh to the Node
[docs]class NodeVM(lago.vm.DefaultVM):
[docs] def _artifact_paths(self): return []
[docs] def wait_for_ssh(self): return
[docs]class EngineVM(lago.vm.DefaultVM): def __init__(self, *args, **kwargs): super(EngineVM, self).__init__(*args, **kwargs) self._api_v3 = None self._api_v4 = None
[docs] def stop(self): super(EngineVM, self).stop() self._api_v3 = None
[docs] def _artifact_paths(self): inherited_artifacts = super(EngineVM, self)._artifact_paths() return set(inherited_artifacts + ['/var/log'])
[docs] def _create_api(self, api_ver): url = 'https://%s/ovirt-engine/api' % self.ip() if api_ver == 3: return ovirtsdk.api.API( url=url, username=constants.ENGINE_USER, password=str(self.metadata['ovirt-engine-password']), validate_cert_chain=False, insecure=True, ) if api_ver == 4: if not API_V4: raise RuntimeError('oVirt Python SDK v4 not found.') return sdk4.Connection( url=url, username=constants.ENGINE_USER, password=str(self.metadata['ovirt-engine-password']), insecure=True, debug=True, ) raise RuntimeError('Unknown API requested: %s' % api_ver)
[docs] def _get_api(self, api_ver): try: api_v3 = [] api_v4 = [] def get(): instance = self._create_api(api_ver) if instance: if api_ver == 3: api_v3.append(instance) else: api_v4.append(instance) return True return False testlib.assert_true_within_short( get, allowed_exceptions=[RequestError, ConnectionError], ) except AssertionError: raise RuntimeError('Failed to connect to the engine') if api_ver == 3: return api_v3.pop() else: testapi = api_v4.pop() counter = 1 while not testapi.test(): if counter == 20: raise RuntimeError('test api call failed') else: time.sleep(3) counter += 1 return testapi
[docs] def get_api(self, api_ver=3): if api_ver == 3: return self.get_api_v3() if api_ver == 4: return self.get_api_v4()
[docs] def get_api_v3(self): if self._api_v3 is None or not self._api_v3.test(): self._api_v3 = self._get_api(api_ver=3) return self._api_v3
[docs] def get_api_v4(self): if self._api_v4 is None or not self._api_v4.test(): self._api_v4 = self._get_api(api_ver=4) return self._api_v4
[docs] def add_iso(self, path): iso_name = os.path.basename(path) self.copy_to(path, '.') ret = self.ssh( [ 'ovirt-iso-uploader', '--conf-file=/root/iso-uploader.conf', '--insecure', iso_name, ] ) if ret: raise RuntimeError('Failed to upload iso to ovirt') ret = self.ssh(['rm', iso_name]) if ret: raise RuntimeError('Failed to remove uploaded image')
[docs] def engine_setup(self, config=None): self.wait_for_ssh() if config: self.copy_to(config, 'engine-answer-file') result = self.interactive_ssh( ['engine-setup', ] + (config and ['--config-append=engine-answer-file'] or []), ) if result.code != 0: raise RuntimeError('Failed to setup the engine')
[docs] def stop_all_vms(self): api = self.get_api_v4() if api is None: raise RuntimeError('Could not connect to engine') vms_service = api.system_service().vms_service() vms = vms_service.list(search='status=up') if vms: for v in vms: vm_service = vms_service.vm_service(v.id) vm_service.stop() time.sleep(10) def _vm_is_down(): vm_srv = vms_service.vm_service(v.id) vm_obj = vm_srv.get() if vm_obj.status == sdk4.types.VmStatus.DOWN: return True for v in vms: testlib.assert_true_within(_vm_is_down, timeout=5 * 60)
[docs] def stop_all_hosts(self): api = self.get_api_v4() if api is None: raise RuntimeError('Could not connect to engine') hosts_service = api.system_service().hosts_service() hosts = hosts_service.list(search='status=up') if hosts: self.stop_all_vms() for h in hosts: host_service = hosts_service.host_service(h.id) host_service.deactivate() time.sleep(10) def _host_is_maint(): h_service = hosts_service.host_service(h.id) host_obj = h_service.get() if host_obj.status == sdk4.types.HostStatus.MAINTENANCE: return True if host_obj.status == sdk4.types.HostStatus.NON_OPERATIONAL: raise RuntimeError( 'Host %s is in non operational state' % h.name ) elif host_obj.status == sdk4.types.HostStatus.INSTALL_FAILED: raise RuntimeError('Host %s installation failed' % h.name) elif host_obj.status == sdk4.types.HostStatus.NON_RESPONSIVE: raise RuntimeError( 'Host %s is in non responsive state' % h.name ) for h in hosts: testlib.assert_true_within(_host_is_maint, timeout=5 * 60)
[docs] def start_all_hosts(self): api = self.get_api_v4() if api is None: raise RuntimeError('Could not connect to engine') hosts_service = api.system_service().hosts_service() hosts = hosts_service.list(search='status=maintenance') if hosts: for h in hosts: host_service = hosts_service.host_service(h.id) host_service.activate() time.sleep(10) def _host_is_up(): h_service = hosts_service.host_service(h.id) host_obj = h_service.get() if host_obj.status == sdk4.types.HostStatus.UP: return True if host_obj.status == sdk4.types.HostStatus.NON_OPERATIONAL: raise RuntimeError( 'Host %s is in non operational state' % h.name ) elif host_obj.status == sdk4.types.HostStatus.INSTALL_FAILED: raise RuntimeError('Host %s installation failed' % h.name) elif host_obj.status == sdk4.types.HostStatus.NON_RESPONSIVE: raise RuntimeError( 'Host %s is in non responsive state' % h.name ) for h in hosts: testlib.assert_true_within(_host_is_up, timeout=5 * 60)
[docs] def status(self): api = self.get_api_v4() if api is None: raise RuntimeError('Could not connect to engine') sys_service = api.system_service().get() print("Version: %s" % sys_service.product_info.version.full_version) print("Hosts: %d" % sys_service.summary.hosts.total) print("SDs: %d" % sys_service.summary.storage_domains.total) print("Users: %d" % sys_service.summary.users.total) print("Vms: %d" % sys_service.summary.vms.total)
[docs]class HostVM(lago.vm.DefaultVM):
[docs] def _artifact_paths(self): inherited_artifacts = super(HostVM, self)._artifact_paths() return set(inherited_artifacts + ['/var/log', ])
[docs]class HEHostVM(HostVM):
[docs] def _artifact_paths(self): inherited_artifacts = super(HEHostVM, self)._artifact_paths() return set(inherited_artifacts)