Skip to content

Commit

Permalink
Merge pull request #773 from galitf/copy_from_vm_squash
Browse files Browse the repository at this point in the history
  • Loading branch information
ovirt-infra authored Dec 9, 2018
2 parents 24fe9b0 + 3210f40 commit 7024fb7
Showing 1 changed file with 60 additions and 50 deletions.
110 changes: 60 additions & 50 deletions lago/plugins/vm.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
import os
import warnings
from abc import (ABCMeta, abstractmethod)

from scp import SCPClient, SCPException

from .. import (
Expand All @@ -50,7 +49,7 @@
LogTask = functools.partial(log_utils.LogTask, logger=LOGGER)


class VMError(Exception):
class VMError(utils.LagoException):
pass


Expand All @@ -59,14 +58,31 @@ class ExtractPathError(VMError):


class ExtractPathNoPathError(VMError):
pass
def __init__(self, err):
super().__init__('Failed to extract files: {}'.format(err))


class LagoVMNotRunningError(utils.LagoUserException):
def __init__(self, vm_name):
super().__init__('VM {} is not running'.format(vm_name))


class LagoCopyFilesToVMError(utils.LagoUserException):
def __init__(self, local_files, err):
super().__init__(
'Failed to copy files/directory {}\n{}'.format(local_files, err)
)


class LagoCopyFilesFromVMError(utils.LagoUserException):
def __init__(self, remote_files, local_files, err=''):
super().__init__(
'Failed to copy files/directory from {} to {}\n{}'.format(
remote_files, local_files, err
)
)


class LagoVMDoesNotExistError(utils.LagoException):
pass

Expand All @@ -91,7 +107,6 @@ class VMProviderPlugin(plugins.Plugin):
you have to inherit from this class, and then define the
'default_vm_provider' in your config to be your plugin, or explicitly
specify it on each domain definition in the initfile with 'vm-provider' key
You will have to override at least all the abstractmethods in order to
write a provider plugin, even if they are just runnig `pass`.
"""
Expand All @@ -103,7 +118,6 @@ def __init__(self, vm):
def start(self, *args, **kwargs):
"""
Start a domain
Returns:
None
"""
Expand All @@ -113,7 +127,6 @@ def start(self, *args, **kwargs):
def stop(self, *args, **kwargs):
"""
Stop a domain
Returns:
None
"""
Expand All @@ -123,7 +136,6 @@ def stop(self, *args, **kwargs):
def shutdown(self, *args, **kwargs):
"""
Shutdown a domain
Returns:
None
"""
Expand All @@ -133,7 +145,6 @@ def shutdown(self, *args, **kwargs):
def reboot(self, *args, **kwargs):
"""
Reboot a domain
Returns:
None
"""
Expand All @@ -144,7 +155,6 @@ def bootstrap(self, *args, **kwargs):
"""
Does any actions needed to get the domain ready to be used, ran on
prefix init.
Return:
None
"""
Expand All @@ -154,7 +164,6 @@ def bootstrap(self, *args, **kwargs):
def state(self, *args, **kwargs):
"""
Return the current state of the domain
Returns:
str: Small description of the current domain state
"""
Expand All @@ -172,11 +181,9 @@ def running(self, *args, **kwargs):
def create_snapshot(self, name, *args, **kwargs):
"""
Take any actions needed to create a snapshot
Args:
name(str): Name for the snapshot, will be used as key to retrieve
it later
Returns:
None
"""
Expand All @@ -186,10 +193,8 @@ def create_snapshot(self, name, *args, **kwargs):
def revert_snapshot(self, name, *args, **kwargs):
"""
Take any actions needed to revert/restore a snapshot
Args:
name(str): Name for the snapshot, same that was set on creation
Returns:
None
"""
Expand All @@ -198,7 +203,6 @@ def revert_snapshot(self, name, *args, **kwargs):
def export_disks(self, standalone, dst_dir, compress, *args, **kwargs):
"""
Export 'disks' as a standalone image or a layered image.
Args:
disks(list): The names of the disks to export
(None means all the disks)
Expand All @@ -213,7 +217,6 @@ def export_disks(self, standalone, dst_dir, compress, *args, **kwargs):
def interactive_console(self):
"""
Run an interactive console
Returns:
lago.utils.CommandStatus: resulf of the interactive execution
"""
Expand All @@ -232,14 +235,11 @@ def name(self):
def extract_paths(self, paths, ignore_nopath):
"""
Extract the given paths from the domain
Args:
paths(list of str): paths to extract
ignore_nopath(boolean): if True will ignore none existing paths.
Returns:
None
Raises:
:exc:`~lago.plugins.vm.ExtractPathNoPathError`: if a none existing
path was found on the VM, and ``ignore_nopath`` is True.
Expand All @@ -266,17 +266,14 @@ def _extract_paths_scp(self, paths, ignore_nopath):
self.vm.copy_from(
local_path=guest_path,
remote_path=host_path,
propagate_fail=False
propagate_fail=not ignore_nopath
)
except SCPException as err:
err_substr = ': No such file or directory'
if len(err.args) > 0 and isinstance(
err.args[0], basestring
) and err_substr in err.args[0]:
if ignore_nopath:
LOGGER.debug('%s: ignoring', err.args[0])
else:
raise ExtractPathNoPathError(err.args[0])
except ExtractPathNoPathError as err:
if ignore_nopath:
LOGGER.debug(
'%s: ignoring since ignore_nopath was set to True',
err.args[0]
)
else:
raise

Expand All @@ -288,9 +285,7 @@ class VMPlugin(plugins.Plugin):
the initfile lingo). From starting/stopping it to loading and calling the
provider if needed. If you want to change only the way the VM is
provisioned you can take a look to the `class:VMProviderPlugin` instead.
This base class includes also some basic methods implemented with ssh.
VM properties:
* name
* cpus
Expand Down Expand Up @@ -411,22 +406,44 @@ def copy_to(self, local_path, remote_path, recursive=True):
with LogTask(
'Copy %s to %s:%s' % (local_path, self.name(), remote_path),
):
with self._scp() as scp:
scp.put(
files=local_path,
remote_path=remote_path,
recursive=recursive,
)
try:
with self._scp() as scp:
scp.put(
files=local_path,
remote_path=remote_path,
recursive=recursive,
)
except (OSError, SCPException) as err:
raise LagoCopyFilesToVMError(local_path, str(err))

def copy_from(
self, remote_path, local_path, recursive=True, propagate_fail=True
):
with self._scp(propagate_fail=propagate_fail) as scp:
scp.get(
recursive=recursive,
remote_path=remote_path,
local_path=local_path,
)
with LogTask(
'Copy from %s:%s to %s' % (self.name(), remote_path, local_path),
propagate_fail=propagate_fail
):
try:
with self._scp(propagate_fail=propagate_fail) as scp:
scp.get(
recursive=recursive,
remote_path=remote_path,
local_path=local_path,
)
except SCPException as err:
err_substr = ': No such file or directory'
if all(
(
len(err.args) > 0,
isinstance(err.args[0], basestring),
err_substr in err.args[0],
)
):
raise ExtractPathNoPathError(err.args[0])
else:
raise LagoCopyFilesFromVMError(
remote_path, local_path, err.args[0]
)

@property
def metadata(self):
Expand Down Expand Up @@ -553,13 +570,11 @@ def ssh_script(self, path, show_output=True):
def ssh_reachable(self, tries=None, propagate_fail=True):
"""
Check if the VM is reachable with ssh
Args:
tries(int): Number of tries to try connecting to the host
propagate_fail(bool): If set to true, this event will appear
in the log and fail the outter stage. Otherwise, it will be
discarded.
Returns:
bool: True if the VM is reachable.
"""
Expand Down Expand Up @@ -736,7 +751,6 @@ def _get_service_provider(self):
"""
**NOTE**: Can be reduced to just one get call once we remove support
for the service_class spec entry
Returns:
class: class for the loaded provider for that vm_spec
None: if no provider was specified in the vm_spec
Expand Down Expand Up @@ -764,18 +778,14 @@ def _resolve_service_class(class_name, service_providers):
"""
**NOTE**: This must be remved once the service_class spec entry is fully
deprecated
Retrieves a service plugin class from the class name instead of the
provider name
Args:
class_name(str): Class name of the service plugin to retrieve
service_providers(dict): provider_name->provider_class of the loaded
service providers
Returns:
class: Class of the plugin that matches that name
Raises:
lago.plugins.NoSuchPluginError: if there was no service plugin that
matched the search
Expand Down

0 comments on commit 7024fb7

Please sign in to comment.