Beispiel #1
0
def sync_node_time(env, node_name='admin', cmd=None):
    if cmd is None:
        cmd = "hwclock -s && NTPD=$(find /etc/init.d/ -regex "
        cmd += "'/etc/init.d/ntp.?'); $NTPD stop; killall ntpd;"
        cmd += " ntpd -qg && $NTPD start"

    if node_name == 'admin':
        try:
            # If public NTP servers aren't accessible ntpdate will fail and
            # ntpd daemon shouldn't be restarted to avoid 'Server has gone
            # too long without sync' error while syncing time from slaves
            remote = get_admin_remote(env)
            remote.execute("ntpdate -d $(awk '/^server/{print"
                           " $2}' /etc/ntp.conf)")
        except AssertionError as e:
            logger.warning('Error occurred while synchronizing time on master'
                           ': {0}'.format(e))
        else:
            remote = get_admin_remote(env)
            remote.execute('service ntpd stop && ntpd -qg && '
                           'service ntpd start')
    else:
        remote = get_node_remote(env, node_name)
        remote.execute(cmd)
    remote.execute('hwclock -w')
    remote_date = remote.execute('date')['stdout']
    logger.info("Node time: {0}".format(remote_date))
Beispiel #2
0
    def synchronize_all(cls):
        driver = cls.get_driver()
        nodes = {
            driver._get_name(e.name, n.name): n
            for e in cls.list_all() for n in e.get_nodes()
        }
        domains = set(driver.node_list())

        # FIXME (AWoodward) This willy nilly wacks domains when you run this
        #  on domains that are outside the scope of devops, if anything this
        #  should cause domains to be imported into db instead of undefined.
        #  It also leaves network and volumes around too
        #  Disabled untill a safer implmentation arrives

        # Undefine domains without devops nodes
        #
        # domains_to_undefine = domains - set(nodes.keys())
        # for d in domains_to_undefine:
        #    driver.node_undefine_by_name(d)

        # Remove devops nodes without domains
        nodes_to_remove = set(nodes.keys()) - domains
        for n in nodes_to_remove:
            nodes[n].delete()
        cls.erase_empty()

        logger.info('Undefined domains: {0}, removed nodes: {1}'.format(
            0, len(nodes_to_remove)))
Beispiel #3
0
    def describe_environment(cls, boot_from='cdrom'):
        environment = cls.create(settings.ENV_NAME)
        networks = []
        interfaces = settings.INTERFACE_ORDER
        if settings.MULTIPLE_NETWORKS:
            logger.info('Multiple cluster networks feature is enabled!')
        if settings.BONDING:
            interfaces = settings.BONDING_INTERFACES.keys()

        for name in interfaces:
            networks.append(environment.create_networks(name))
        for name in environment.node_roles.admin_names:
            environment.describe_admin_node(name, networks, boot_from)
        for name in environment.node_roles.other_names:
            networks_to_describe = networks
            if settings.MULTIPLE_NETWORKS:
                # If slave index is even number, then attach to
                # it virtual networks from the second network group,
                # if it is odd, then attach from the first network group.
                nodegroups_idx = 1 - int(name[-2:]) % 2
                networks_to_describe = [
                    net for net in networks if net.name
                    in settings.NODEGROUPS[nodegroups_idx]['pools']
                ]

            environment.describe_empty_node(name, networks_to_describe)
        for name in environment.node_roles.ironic_names:
            ironic_net = []
            for net in networks:
                if net.name == 'ironic':
                    ironic_net.append(net)
            environment.describe_empty_node(name, ironic_net)
        return environment
    def execute(self, command, verbose=False, timeout=None, **kwargs):
        """Execute command and wait for return code

        :type command: str
        :type verbose: bool
        :type timeout: int
        :rtype: ExecResult
        :raises: TimeoutError
        """
        chan, _, stderr, stdout = self.execute_async(command, **kwargs)

        result = self.__exec_command(command,
                                     chan,
                                     stdout,
                                     stderr,
                                     timeout,
                                     verbose=verbose)

        message = ('\n{cmd!r} execution results: Exit code: {code!s}'.format(
            cmd=command, code=result.exit_code))
        if verbose:
            logger.info(message)
        else:
            logger.debug(message)
        return result
Beispiel #5
0
    def revert(self, name=None, destroy=True):
        """Method to revert node in state from snapshot

           For external snapshots in libvirt we use restore function.
           After reverting in this way we get situation when node is connected
           to original volume disk, without snapshot point. To solve this
           problem we need to switch it to correct volume.

           In case of usage external snapshots we clean snapshot disk when
           revert to snapshot without childs and create new snapshot point
           when reverting to snapshots with childs.
        """
        if destroy:
            self.destroy()
        if self.has_snapshot(name):
            snapshot = self._get_snapshot(name)

            if snapshot.get_type == 'external':
                # EXTERNAL SNAPSHOT
                self._revert_external_snapshot(name)
            else:
                # ORIGINAL SNAPSHOT
                logger.info("Revert {0} ({1}) to internal snapshot {2}".format(
                    self.name, snapshot.state, name))
                self._libvirt_node.revertToSnapshot(snapshot._snapshot, 0)

        else:
            raise DevopsError(
                'Domain snapshot for {0} node not found: no domain '
                'snapshot with matching'
                ' name {1}'.format(self.name, name))
Beispiel #6
0
    def revert(self, name=None, destroy=True):
        """Method to revert node in state from snapshot

           For external snapshots in libvirt we use restore function.
           After reverting in this way we get situation when node is connected
           to original volume disk, without snapshot point. To solve this
           problem we need to switch it to correct volume.

           In case of usage external snapshots we clean snapshot disk when
           revert to snapshot without childs and create new snapshot point
           when reverting to snapshots with childs.
        """
        if destroy:
            self.destroy()
        if self.has_snapshot(name):
            snapshot = self._get_snapshot(name)

            if snapshot.get_type == 'external':
                # EXTERNAL SNAPSHOT
                self._revert_external_snapshot(name)
            else:
                # ORIGINAL SNAPSHOT
                logger.info("Revert {0} ({1}) to internal snapshot {2}".format(
                    self.name, snapshot.state, name))
                self._libvirt_node.revertToSnapshot(snapshot._snapshot, 0)

        else:
            raise DevopsError(
                'Domain snapshot for {0} node not found: no domain '
                'snapshot with matching'
                ' name {1}'.format(self.name, name))
Beispiel #7
0
    def describe_environment(cls, boot_from='cdrom'):
        environment = cls.create(settings.ENV_NAME)
        networks = []
        interfaces = settings.INTERFACE_ORDER
        if settings.MULTIPLE_NETWORKS:
            logger.info('Multiple cluster networks feature is enabled!')
        if settings.BONDING:
            interfaces = settings.BONDING_INTERFACES.keys()

        for name in interfaces:
            networks.append(environment.create_networks(name))
        for name in environment.node_roles.admin_names:
            environment.describe_admin_node(name, networks, boot_from)
        for name in environment.node_roles.other_names:
            if settings.MULTIPLE_NETWORKS:
                networks1 = [net for net in networks if net.name
                             in settings.NODEGROUPS[0]['pools']]
                networks2 = [net for net in networks if net.name
                             in settings.NODEGROUPS[1]['pools']]
                # If slave index is even number, then attach to
                # it virtual networks from the second network group.
                if int(name[-2:]) % 2 == 1:
                    environment.describe_empty_node(name, networks1)
                elif int(name[-2:]) % 2 == 0:
                    environment.describe_empty_node(name, networks2)
            else:
                environment.describe_empty_node(name, networks)
        return environment
Beispiel #8
0
    def synchronize_all(cls):
        driver = cls.get_driver()
        nodes = {driver._get_name(e.name, n.name): n
                 for e in cls.list_all()
                 for n in e.get_nodes()}
        domains = set(driver.node_list())

        # FIXME (AWoodward) This willy nilly wacks domains when you run this
        #  on domains that are outside the scope of devops, if anything this
        #  should cause domains to be imported into db instead of undefined.
        #  It also leaves network and volumes around too
        #  Disabled untill a safer implmentation arrives

        # Undefine domains without devops nodes
        #
        # domains_to_undefine = domains - set(nodes.keys())
        # for d in domains_to_undefine:
        #    driver.node_undefine_by_name(d)

        # Remove devops nodes without domains
        nodes_to_remove = set(nodes.keys()) - domains
        for n in nodes_to_remove:
            nodes[n].delete()
        cls.erase_empty()

        logger.info('Undefined domains: {0}, removed nodes: {1}'.format(
            0, len(nodes_to_remove)
        ))
Beispiel #9
0
    def describe_environment(cls, boot_from='cdrom'):
        environment = cls.create(settings.ENV_NAME)
        networks = []
        interfaces = settings.INTERFACE_ORDER
        if settings.MULTIPLE_NETWORKS:
            logger.info('Multiple cluster networks feature is enabled!')
        if settings.BONDING:
            interfaces = settings.BONDING_INTERFACES.keys()

        for name in interfaces:
            networks.append(environment.create_networks(name))
        for name in environment.node_roles.admin_names:
            environment.describe_admin_node(name, networks, boot_from)
        for name in environment.node_roles.other_names:
            if settings.MULTIPLE_NETWORKS:
                networks1 = [
                    net for net in networks
                    if net.name in settings.NODEGROUPS[0]['pools']
                ]
                networks2 = [
                    net for net in networks
                    if net.name in settings.NODEGROUPS[1]['pools']
                ]
                # If slave index is even number, then attach to
                # it virtual networks from the second network group.
                if int(name[-2:]) % 2 == 1:
                    environment.describe_empty_node(name, networks1)
                elif int(name[-2:]) % 2 == 0:
                    environment.describe_empty_node(name, networks2)
            else:
                environment.describe_empty_node(name, networks)
        return environment
 def bootstrap_and_wait(self):
     self.node.start()
     ip = self.node.get_ip_address_by_network_name(
         settings.SSH_CREDENTIALS['admin_network'])
     wait_tcp(host=ip, port=self.node.ssh_port,
              timeout=self.node.bootstrap_timeout,
              timeout_msg='Failed to bootstrap centos master')
     logger.info('Centos cloud image bootstrap complete')
 def bootstrap_and_wait(self):
     self.node.start()
     ip = self.node.get_ip_address_by_network_name(
         settings.SSH_CREDENTIALS['admin_network'])
     helpers.wait_tcp(host=ip,
                      port=self.node.ssh_port,
                      timeout=self.node.bootstrap_timeout,
                      timeout_msg='Failed to bootstrap centos master')
     logger.info('Centos cloud image bootstrap complete')
Beispiel #12
0
def sync_node_time(env, node_name='admin', cmd=None):
    if cmd is None:
        cmd = "hwclock -s"

    if node_name == 'admin':
        remote = get_admin_remote(env)
    else:
        remote = get_node_remote(env, node_name)
    remote.execute(cmd)
    remote_date = remote.execute('date')['stdout']
    logger.info("Node time: {0}".format(remote_date))
    return remote_date
Beispiel #13
0
def sync_node_time(env, node_name='admin', cmd=None):
    if cmd is None:
        cmd = "hwclock -s"

    if node_name == 'admin':
            remote = get_admin_remote(env)
    else:
        remote = get_node_remote(env, node_name)
    remote.execute(cmd)
    remote_date = remote.execute('date')['stdout']
    logger.info("Node time: {0}".format(remote_date))
    return remote_date
Beispiel #14
0
    def __init__(
            self,
            host, port=22,
            username=None, password=None, private_keys=None,
            auth=None, verbose=True
    ):
        """SSHClient helper

        :type host: str
        :type port: int
        :type username: str
        :type password: str
        :type private_keys: list
        :type auth: SSHAuth
        :type verbose: bool, show additional error/warning messages
        """
        self.__lock = threading.RLock()

        self.__hostname = host
        self.__port = port

        self.sudo_mode = False
        self.__ssh = paramiko.SSHClient()
        self.__ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        self.__sftp = None

        self.__auth = auth if auth is None else auth.copy()
        self.__verbose = verbose

        if auth is None:
            msg = (
                'SSHClient(host={host}, port={port}, username={username}): '
                'initialization by username/password/private_keys '
                'is deprecated in favor of SSHAuth usage. '
                'Please update your code'.format(
                    host=host, port=port, username=username
                ))
            warnings.warn(msg, DeprecationWarning)
            logger.debug(msg)

            self.__auth = SSHAuth(
                username=username,
                password=password,
                keys=private_keys
            )

        self.__connect()
        _MemorizedSSH.record(ssh=self)
        if auth is None:
            logger.info(
                '{0}:{1}> SSHAuth was made from old style creds: '
                '{2}'.format(self.hostname, self.port, self.auth))
Beispiel #15
0
 def node_define(self, node):
     """
     :type node: Node
         :rtype : None
     """
     emulator = self.get_capabilities(
     ).find(
         'guest/arch[@name="{0:>s}"]/'
         'domain[@type="{1:>s}"]/emulator'.format(
             node.architecture, node.hypervisor)).text
     node_xml = self.xml_builder.build_node_xml(node, emulator)
     logger.info(node_xml)
     node.uuid = self.conn.defineXML(node_xml).UUIDString()
Beispiel #16
0
    def execute_through_host(
            self,
            target_host,
            cmd,
            username=None,
            password=None,
            key=None,
            target_port=22):
        if username is None and password is None and key is None:
            username = self.username
            password = self.__password
            key = self.private_key

        intermediate_channel = self._ssh.get_transport().open_channel(
            'direct-tcpip', (target_host, target_port), (self.host, 0))
        transport = paramiko.Transport(intermediate_channel)
        transport.start_client()
        logger.info("Passing authentication to: {}".format(target_host))
        if password is None and key is None:
            logger.debug('auth_none')
            transport.auth_none(username=username)
        elif key is not None:
            logger.debug('auth_publickey')
            transport.auth_publickey(username=username, key=key)
        else:
            logger.debug('auth_password')
            transport.auth_password(username=username, password=password)

        logger.debug("Opening session")
        channel = transport.open_session()

        # Make proxy objects for read
        stdout = channel.makefile('rb')
        stderr = channel.makefile_stderr('rb')

        logger.info("Executing command: {}".format(cmd))
        channel.exec_command(cmd)

        # TODO(astepanov): make a logic for controlling channel state
        # noinspection PyDictCreation
        result = {}
        result['exit_code'] = channel.recv_exit_status()

        result['stdout'] = stdout.read()
        result['stderr'] = stderr.read()
        channel.close()

        result['stdout_str'] = ''.join(result['stdout']).strip()
        result['stderr_str'] = ''.join(result['stderr']).strip()

        return result
    def node_revert_snapshot(self, node, name=None):
        """Revert snapshot for node

        :type node: Node
        :type name: String
            :rtype : None
        """
        domain = self.conn.lookupByUUIDString(node.uuid)
        snapshot = Snapshot(self._get_snapshot(domain, name))

        if snapshot.get_type == 'external':
            logger.info("Revert {0} ({1}) from external snapshot {2}".format(
                node.name, snapshot.state, name))

            if self.node_active(node):
                self.node_destroy(node)

            # When snapshot dont have children we need to update disks in XML
            # used for reverting, standard revert function will restore links
            # to original disks, but we need to use disks with snapshot point,
            # we dont want to change original data
            #
            # For snapshot with children we need to create new snapshot chain
            # and we need to start from original disks, this disks will get new
            # snapshot point in node class
            xml_domain = snapshot._xml_tree.find('domain')
            if snapshot.children_num == 0:
                domain_disks = xml_domain.findall('./devices/disk')
                for s_disk, s_disk_data in snapshot.disks.items():
                    for d_disk in domain_disks:
                        d_disk_dev = d_disk.find('target').get('dev')
                        d_disk_device = d_disk.get('device')
                        if d_disk_dev == s_disk and d_disk_device == 'disk':
                            d_disk.find('source').set('file', s_disk_data)

            if snapshot.state == 'shutoff':
                # Redefine domain for snapshot without memory save
                self.conn.defineXML(ET.tostring(xml_domain))
            else:
                self.conn.restoreFlags(
                    snapshot.memory_file,
                    dxml=ET.tostring(xml_domain),
                    flags=libvirt.VIR_DOMAIN_SAVE_PAUSED)

            # set snapshot as current
            self.node_set_snapshot_current(node, name)

        else:
            logger.info("Revert {0} ({1}) to internal snapshot {2}".format(
                node.name, snapshot.state, name))
            domain.revertToSnapshot(snapshot._snapshot, 0)
Beispiel #18
0
 def delete_snapshot_files(self):
     """Delete snapshot external files"""
     snap_type = self.get_type
     if snap_type == 'external':
         for snap_file in self.__snapshot_files:
             if os.path.isfile(snap_file):
                 try:
                     os.remove(snap_file)
                     logger.info("Delete external snapshot file {0}".format(
                         snap_file))
                 except Exception:
                     logger.info("Cannot delete external snapshot file {0}"
                                 " must be deleted from cron script".format(
                                     snap_file))
Beispiel #19
0
 def execute(self, command, verbose=False):
     chan, stdin, stderr, stdout = self.execute_async(command)
     result = {'stdout': [], 'stderr': [], 'exit_code': 0}
     for line in stdout:
         result['stdout'].append(line)
         if verbose:
             logger.info(line)
     for line in stderr:
         result['stderr'].append(line)
         if verbose:
             logger.info(line)
     result['exit_code'] = chan.recv_exit_status()
     chan.close()
     return result
    def start(self):
        """Start the node (power on)"""
        logger.info(
            "Starting Ironic node {0}(uuid={1}) with timeout={2}".format(
                self.name, self.uuid, self.wait_active_timeout))

        self.wait_for_state(expected_state='active',
                            timeout=self.wait_active_timeout)

        self.driver.conn.node.set_power_state(
            node_id=self.uuid,
            state='on',
        )
        super(IronicNode, self).start()
Beispiel #21
0
    def _node_revert_snapshot_recreate_disks(self, name):
        """Recreate snapshot disks."""
        snapshot = self._get_snapshot(name)

        if snapshot.children_num == 0:
            for s_disk_data in snapshot.disks.values():
                logger.info("Recreate {0}".format(s_disk_data))

                # Save actual volume XML, delete volume and create
                # new from saved XML
                volume = self.driver.conn.storageVolLookupByKey(s_disk_data)
                volume_xml = volume.XMLDesc()
                volume_pool = volume.storagePoolLookupByVolume()
                volume.delete()
                volume_pool.createXML(volume_xml)
Beispiel #22
0
    def _node_revert_snapshot_recreate_disks(self, name):
        """Recreate snapshot disks."""
        snapshot = self._get_snapshot(name)

        if snapshot.children_num == 0:
            for s_disk_data in snapshot.disks.values():
                logger.info("Recreate {0}".format(s_disk_data))

                # Save actual volume XML, delete volume and create
                # new from saved XML
                volume = self.driver.conn.storageVolLookupByKey(s_disk_data)
                volume_xml = volume.XMLDesc()
                volume_pool = volume.storagePoolLookupByVolume()
                volume.delete()
                volume_pool.createXML(volume_xml)
    def node_revert_snapshot_recreate_disks(self, node, name):
        """Recreate snapshot disks."""
        domain = self.conn.lookupByUUIDString(node.uuid)
        snapshot = Snapshot(self._get_snapshot(domain, name))

        if snapshot.children_num == 0:
            for s_disk, s_disk_data in snapshot.disks.items():
                logger.info("Recreate {0}".format(s_disk_data))

                # Save actual volume XML, delete volume and create
                # new from saved XML
                volume = self.conn.storageVolLookupByKey(s_disk_data)
                volume_xml = volume.XMLDesc()
                volume_pool = volume.storagePoolLookupByVolume()
                volume.delete()
                volume_pool.createXML(volume_xml)
Beispiel #24
0
 def delete_snapshot_files(self):
     """Delete snapshot external files"""
     snap_type = self.get_type
     if snap_type == 'external':
         for snap_file in self.__snapshot_files:
             if os.path.isfile(snap_file):
                 try:
                     os.remove(snap_file)
                     logger.info(
                         "Delete external snapshot file {0}".format(
                             snap_file))
                 except Exception:
                     logger.info(
                         "Cannot delete external snapshot file {0}"
                         " must be deleted from cron script".format(
                             snap_file))
 def remove(self, *args, **kwargs):
     if self.uuid:
         if self.exists():
             #    self.destroy()
             logger.info("Removing Ironic node {0}(uuid={1})".format(
                 self.name, self.uuid))
             try:
                 self.driver.conn.node.set_maintenance(
                     node_id=self.uuid,
                     state=True,
                     maint_reason="Removing the node from devops environment"
                 )
                 self.driver.conn.node.delete(self.uuid)
             except common.apiclient.exceptions.BadRequest:
                 # Allow to remove node from fuel-devops if ironic API down
                 pass
     super(IronicNode, self).remove()
Beispiel #26
0
 def execute(self, command, verbose=False):
     chan, _, stderr, stdout = self.execute_async(command)
     result = {
         'stdout': [],
         'stderr': [],
         'exit_code': 0
     }
     for line in stdout:
         result['stdout'].append(line)
         if verbose:
             logger.info(line)
     for line in stderr:
         result['stderr'].append(line)
         if verbose:
             logger.info(line)
     result['exit_code'] = chan.recv_exit_status()
     chan.close()
     return result
Beispiel #27
0
    def synchronize_all(self):
        nodes = {self.get_driver()._get_name(e.name, n.name): n
                 for e in Environment.objects.all()
                 for n in e.nodes}
        domains = set(self.driver.node_list())

        # Undefine domains without devops nodes
        domains_to_undefine = domains - set(nodes.keys())
        for d in domains_to_undefine:
            self.driver.node_undefine_by_name(d)

        # Remove devops nodes without domains
        nodes_to_remove = set(nodes.keys()) - domains
        for n in nodes_to_remove:
            nodes[n].delete()
        Environment.erase_empty()

        logger.info('Undefined domains: %s, removed nodes: %s',
                    (len(domains_to_undefine), len(nodes_to_remove)))
Beispiel #28
0
    def synchronize_all(self):
        nodes = {
            self.get_driver()._get_name(e.name, n.name): n
            for e in Environment.objects.all() for n in e.nodes
        }
        domains = set(self.driver.node_list())

        # Undefine domains without devops nodes
        domains_to_undefine = domains - set(nodes.keys())
        for d in domains_to_undefine:
            self.driver.node_undefine_by_name(d)

        # Remove devops nodes without domains
        nodes_to_remove = set(nodes.keys()) - domains
        for n in nodes_to_remove:
            nodes[n].delete()
        Environment.erase_empty()

        logger.info('Undefined domains: %s, removed nodes: %s',
                    (len(domains_to_undefine), len(nodes_to_remove)))
    def execute(cls, command, verbose=False, timeout=None, **kwargs):
        """Execute command and wait for return code

        Timeout limitation: read tick is 100 ms.

        :type command: str
        :type verbose: bool
        :type timeout: int
        :rtype: ExecResult
        :raises: TimeoutError
        """
        result = cls.__exec_command(command=command, timeout=timeout,
                                    verbose=verbose, **kwargs)
        message = log_templates.CMD_RESULT.format(
            cmd=command, code=result.exit_code)
        if verbose:
            logger.info(message)
        else:
            logger.debug(message)

        return result
Beispiel #30
0
 def _start_nfs(self):
     if os.path.isfile('/etc/exports'):
         cmd = ['sudo', 'mv', '/etc/exports', '/etc/exports-devops-last']
         output = subprocess.check_output(cmd)
         LOGGER.info(output)
     cmd = ['sudo', 'touch', '/etc/exports']
     subprocess.call(cmd)
     cmd = ['sudo', 'chown', os.getlogin(), '/etc/exports']
     subprocess.call(cmd)
     f = open('/etc/exports', 'w+')
     f.write('{0}/tftpboot/fuel/ {1}(ro,async,no_subtree_check,fsid=1,'
             'no_root_squash)'.format(self.ipmi_driver_root_dir,
                                      self.ip_node_admin))
     f.close()
     if self.system_init.find('systemd') == 1:
         cmd = ['sudo', 'systemctl', 'restart', 'nfsd']
     else:
         cmd = ['sudo', 'service', 'nfs-kernel-server', 'restart']
     output = subprocess.check_output(cmd)
     LOGGER.debug('NFS server started, output is {0}'.format(output))
     return True
Beispiel #31
0
 def _start_nfs(self):
     if os.path.isfile('/etc/exports'):
         cmd = ['sudo', 'mv', '/etc/exports', '/etc/exports-devops-last']
         output = subprocess.check_output(cmd)
         LOGGER.info(output)
     cmd = ['sudo', 'touch', '/etc/exports']
     subprocess.call(cmd)
     cmd = ['sudo', 'chown', os.getlogin(), '/etc/exports']
     subprocess.call(cmd)
     f = open('/etc/exports', 'w+')
     f.write('{0}/tftpboot/fuel/ {1}(ro,async,no_subtree_check,fsid=1,'
             'no_root_squash)'.format(self.ipmi_driver_root_dir,
                                      self.ip_node_admin))
     f.close()
     if self.system_init.find('systemd') == 1:
         cmd = ['sudo', 'systemctl', 'restart', 'nfsd']
     else:
         cmd = ['sudo', 'service', 'nfs-kernel-server', 'restart']
     output = subprocess.check_output(cmd)
     LOGGER.debug('NFS server started, output is {0}'.format(output))
     return True
Beispiel #32
0
    def execute(self, command, verbose=False, timeout=None, **kwargs):
        """Execute command and wait for return code

        :type command: str
        :type verbose: bool
        :type timeout: int
        :rtype: ExecResult
        :raises: TimeoutError
        """
        chan, _, stderr, stdout = self.execute_async(command, **kwargs)

        result = self.__exec_command(
            command, chan, stdout, stderr, timeout,
            verbose=verbose
        )
        message = (log_templates.CMD_RESULT.format(
                   cmd=command.rstrip(), code=result.exit_code))
        if verbose:
            logger.info(message)
        else:
            logger.debug(message)
        return result
    def execute(cls, command, verbose=False, timeout=None, **kwargs):
        """Execute command and wait for return code

        Timeout limitation: read tick is 100 ms.

        :type command: str
        :type verbose: bool
        :type timeout: int
        :rtype: ExecResult
        :raises: TimeoutError
        """
        result = cls.__exec_command(command=command,
                                    timeout=timeout,
                                    verbose=verbose,
                                    **kwargs)
        message = ('\n{cmd!r} execution results: Exit code: {code!s}'.format(
            cmd=command, code=result.exit_code))
        if verbose:
            logger.info(message)
        else:
            logger.debug(message)

        return result
Beispiel #34
0
    def _revert_external_snapshot(self, name=None):
        snapshot = self._get_snapshot(name)
        self.destroy()
        if snapshot.children_num == 0:
            logger.info("Reuse last snapshot")

            # Update current node disks
            self._update_disks_from_snapshot(name)

            # Recreate volumes for snapshot and reuse it.
            self._node_revert_snapshot_recreate_disks(name)

            # Revert snapshot
            # self.driver.node_revert_snapshot(node=self, name=name)
            self._redefine_external_snapshot(name=name)
        else:
            # Looking for last reverted snapshot without children
            # or create new and start next snapshot chain
            revert_name = name + '-revert'
            revert_count = 0
            create_new = True

            while self.has_snapshot(revert_name):
                # Check wheter revert snapshot has children
                snapshot_revert = self._get_snapshot(revert_name)
                if snapshot_revert.children_num == 0:
                    logger.info(
                        "Revert snapshot exists, clean and reuse it")

                    # Update current node disks
                    self._update_disks_from_snapshot(revert_name)

                    # Recreate volumes
                    self._node_revert_snapshot_recreate_disks(revert_name)

                    # Revert snapshot
                    # self.driver.node_revert_snapshot(
                    #    node=self, name=revert_name)
                    self._redefine_external_snapshot(name=revert_name)
                    create_new = False
                    break
                else:
                    revert_name = name + '-revert' + str(revert_count)
                    revert_count += 1

            if create_new:
                logger.info("Create new revert snapshot")

                # Update current node disks
                self._update_disks_from_snapshot(name)

                # Revert snapshot
                # self.driver.node_revert_snapshot(node=self, name=name)
                self._redefine_external_snapshot(name=name)

                # Create new snapshot
                self.snapshot(name=revert_name, external=True)
Beispiel #35
0
    def _revert_external_snapshot(self, name=None):
        snapshot = self._get_snapshot(name)
        self.destroy()
        if snapshot.children_num == 0:
            logger.info("Reuse last snapshot")

            # Update current node disks
            self._update_disks_from_snapshot(name)

            # Recreate volumes for snapshot and reuse it.
            self._node_revert_snapshot_recreate_disks(name)

            # Revert snapshot
            # self.driver.node_revert_snapshot(node=self, name=name)
            self._redefine_external_snapshot(name=name)
        else:
            # Looking for last reverted snapshot without children
            # or create new and start next snapshot chain
            revert_name = name + '-revert'
            revert_count = 0
            create_new = True

            while self.has_snapshot(revert_name):
                # Check wheter revert snapshot has children
                snapshot_revert = self._get_snapshot(revert_name)
                if snapshot_revert.children_num == 0:
                    logger.info("Revert snapshot exists, clean and reuse it")

                    # Update current node disks
                    self._update_disks_from_snapshot(revert_name)

                    # Recreate volumes
                    self._node_revert_snapshot_recreate_disks(revert_name)

                    # Revert snapshot
                    # self.driver.node_revert_snapshot(
                    #    node=self, name=revert_name)
                    self._redefine_external_snapshot(name=revert_name)
                    create_new = False
                    break
                else:
                    revert_name = name + '-revert' + str(revert_count)
                    revert_count += 1

            if create_new:
                logger.info("Create new revert snapshot")

                # Update current node disks
                self._update_disks_from_snapshot(name)

                # Revert snapshot
                # self.driver.node_revert_snapshot(node=self, name=name)
                self._redefine_external_snapshot(name=name)

                # Create new snapshot
                self.snapshot(name=revert_name, external=True)
Beispiel #36
0
    def _redefine_external_snapshot(self, name=None):
        snapshot = self._get_snapshot(name)

        logger.info("Revert {0} ({1}) from external snapshot {2}".format(
            self.name, snapshot.state, name))

        self.destroy()

        # When snapshot dont have children we need to update disks in XML
        # used for reverting, standard revert function will restore links
        # to original disks, but we need to use disks with snapshot point,
        # we dont want to change original data
        #
        # For snapshot with children we need to create new snapshot chain
        # and we need to start from original disks, this disks will get new
        # snapshot point in node class
        xml_domain = snapshot._xml_tree.find('domain')
        if snapshot.children_num == 0:
            domain_disks = xml_domain.findall('./devices/disk')
            for s_disk, s_disk_data in snapshot.disks.items():
                for d_disk in domain_disks:
                    d_disk_dev = d_disk.find('target').get('dev')
                    d_disk_device = d_disk.get('device')
                    if d_disk_dev == s_disk and d_disk_device == 'disk':
                        d_disk.find('source').set('file', s_disk_data)

        if snapshot.state == 'shutoff':
            # Redefine domain for snapshot without memory save
            self.driver.conn.defineXML(ET.tostring(xml_domain))
        else:
            self.driver.conn.restoreFlags(snapshot.memory_file,
                                          dxml=ET.tostring(xml_domain),
                                          flags=libvirt.VIR_DOMAIN_SAVE_PAUSED)

        # set snapshot as current
        self.set_snapshot_current(name)
    def node_create_snapshot(self, node, name=None, description=None,
                             disk_only=False, external=False):
        """Create snapshot

        :type description: String
        :type name: String
        :type node: Node
            :rtype : None
        """
        if self.node_snapshot_exists(node, name):
            logger.error("Snapshot with name {0} already exists".format(name))
            return

        domain = self.conn.lookupByUUIDString(node.uuid)

        # If domain has snapshots we must check their type
        snap_list = self.node_get_snapshots(node)
        if len(snap_list) > 0:
            snap_type = snap_list[0].get_type
            if external and snap_type == 'internal':
                logger.error(
                    "Cannot create external snapshot when internal exists")
                return
            if not external and snap_type == 'external':
                logger.error(
                    "Cannot create internal snapshot when external exists")
                return

        logger.info(domain.state(0))
        xml = self.xml_builder.build_snapshot_xml(
            name, description, node, disk_only, external,
            settings.SNAPSHOTS_EXTERNAL_DIR)
        logger.info(xml)
        if external:
            # Check whether we have directory for snapshots, if not
            # create it
            if not os.path.exists(settings.SNAPSHOTS_EXTERNAL_DIR):
                os.makedirs(settings.SNAPSHOTS_EXTERNAL_DIR)

            if domain.isActive() and not disk_only:
                domain.snapshotCreateXML(
                    xml,
                    libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT)
            else:
                domain.snapshotCreateXML(
                    xml,
                    libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY |
                    libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT)
            self.node_set_snapshot_current(node, name)
        else:
            domain.snapshotCreateXML(xml)
        logger.info(domain.state(0))
Beispiel #38
0
 def node_create_snapshot(self, node, name=None, description=None):
     """
     :type description: String
     :type name: String
     :type node: Node
         :rtype : None
     """
     xml = self.xml_builder.build_snapshot_xml(name, description)
     logger.info(xml)
     domain = self.conn.lookupByUUIDString(node.uuid)
     logger.info(domain.state(0))
     domain.snapshotCreateXML(xml, 0)
     logger.info(domain.state(0))
Beispiel #39
0
    def define(self):
        """Define node

            :rtype : None
        """
        name = underscored(
            deepgetattr(self, 'group.environment.name'),
            self.name,
        )

        local_disk_devices = []
        for disk in self.disk_devices:
            local_disk_devices.append(dict(
                disk_type=disk.type,
                disk_device=disk.device,
                disk_volume_format=disk.volume.format,
                disk_volume_path=disk.volume.get_path(),
                disk_bus=disk.bus,
                disk_target_dev=disk.target_dev,
                disk_serial=uuid.uuid4().hex,
            ))

        local_interfaces = []
        for interface in self.interfaces:
            if interface.type != 'network':
                raise NotImplementedError(
                    message='Interface types different from network are not '
                            'implemented yet')

            l2_dev = interface.l2_network_device
            local_interfaces.append(dict(
                interface_type=interface.type,
                interface_mac_address=interface.mac_address,
                interface_network_name=l2_dev.network_name(),
                interface_id=interface.id,
                interface_model=interface.model,
            ))

        emulator = self.driver.get_capabilities().find(
            'guest/arch[@name="{0:>s}"]/'
            'domain[@type="{1:>s}"]/emulator'.format(
                self.architecture, self.hypervisor)).text
        node_xml = LibvirtXMLBuilder.build_node_xml(
            name=name,
            hypervisor=self.hypervisor,
            use_host_cpu=self.driver.use_host_cpu,
            vcpu=self.vcpu,
            memory=self.memory,
            use_hugepages=self.driver.use_hugepages,
            hpet=self.driver.hpet,
            os_type=self.os_type,
            architecture=self.architecture,
            boot=self.boot,
            reboot_timeout=self.driver.reboot_timeout,
            bootmenu_timeout=self.bootmenu_timeout,
            emulator=emulator,
            has_vnc=self.has_vnc,
            vnc_password=self.driver.vnc_password,
            local_disk_devices=local_disk_devices,
            interfaces=local_interfaces,
        )
        logger.info(node_xml)
        self.uuid = self.driver.conn.defineXML(node_xml).UUIDString()

        super(Node, self).define()
    def __exec_command(cls,
                       command,
                       cwd=None,
                       env=None,
                       timeout=None,
                       verbose=False):
        """Command executor helper

        :type command: str
        :type cwd: str
        :type env: dict
        :type timeout: int
        :rtype: ExecResult
        """
        def poll_stream(src, verb_logger=None):
            dst = []
            try:
                for line in src:
                    dst.append(line)
                    if verb_logger is not None:
                        verb_logger(
                            line.decode('utf-8',
                                        errors='backslashreplace').rstrip())
            except IOError:
                pass
            return dst

        def poll_streams(result, stdout, stderr, verbose):
            rlist, _, _ = select.select([stdout, stderr], [], [])
            if rlist:
                if stdout in rlist:
                    result.stdout += poll_stream(
                        src=stdout,
                        verb_logger=logger.info if verbose else logger.debug)
                if stderr in rlist:
                    result.stderr += poll_stream(
                        src=stderr,
                        verb_logger=logger.error if verbose else logger.debug)

        @decorators.threaded(started=True)
        def poll_pipes(proc, result, stop):
            """Polling task for FIFO buffers

            :type proc: subprocess.Popen
            :type result: ExecResult
            :type stop: threading.Event
            """
            # Get file descriptors for stdout and stderr streams
            fd_stdout = proc.stdout.fileno()
            fd_stderr = proc.stderr.fileno()
            # Get flags of stdout and stderr streams
            fl_stdout = fcntl.fcntl(fd_stdout, fcntl.F_GETFL)
            fl_stderr = fcntl.fcntl(fd_stderr, fcntl.F_GETFL)
            # Set nonblock mode for stdout and stderr streams
            fcntl.fcntl(fd_stdout, fcntl.F_SETFL, fl_stdout | os.O_NONBLOCK)
            fcntl.fcntl(fd_stderr, fcntl.F_SETFL, fl_stderr | os.O_NONBLOCK)

            while not stop.isSet():
                time.sleep(0.1)
                poll_streams(result=result,
                             stdout=proc.stdout,
                             stderr=proc.stderr,
                             verbose=verbose)

                proc.poll()

                if proc.returncode is not None:
                    result.exit_code = proc.returncode
                    result.stdout += poll_stream(
                        src=proc.stdout,
                        verb_logger=logger.info if verbose else logger.debug)
                    result.stderr += poll_stream(
                        src=proc.stderr,
                        verb_logger=logger.error if verbose else logger.debug)

                    stop.set()

        # 1 Command per run
        with cls.__lock:
            result = exec_result.ExecResult(cmd=command)
            stop_event = threading.Event()

            if verbose:
                logger.info("\nExecuting command: {!r}".format(
                    command.rstrip()))
            else:
                logger.debug("\nExecuting command: {!r}".format(
                    command.rstrip()))
            # Run
            process = subprocess.Popen(args=[command],
                                       stdin=subprocess.PIPE,
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.PIPE,
                                       shell=True,
                                       cwd=cwd,
                                       env=env,
                                       universal_newlines=False)

            # Poll output
            poll_pipes(process, result, stop_event)
            # wait for process close
            stop_event.wait(timeout)

            # Process closed?
            if stop_event.isSet():
                stop_event.clear()
                return result

            # Kill not ended process and wait for close
            try:
                process.kill()  # kill -9
                stop_event.wait(5)

            except OSError:
                # Nothing to kill
                logger.warning("{!r} has been completed just after timeout: "
                               "please validate timeout.".format(command))

            wait_err_msg = (
                'Wait for {0!r} during {1}s: no return code!\n'.format(
                    command, timeout))
            output_brief_msg = ('\tSTDOUT:\n'
                                '{0}\n'
                                '\tSTDERR"\n'
                                '{1}'.format(result.stdout_brief,
                                             result.stderr_brief))
            logger.debug(wait_err_msg)
            raise error.TimeoutError(wait_err_msg + output_brief_msg)
Beispiel #41
0
    def snapshot(self, name=None, force=False, description=None,
                 disk_only=False, external=False):

        # Erase existing snapshot or raise an error if already exists
        if self.has_snapshot(name):
            if force:
                self.erase_snapshot(name)
            else:
                raise DevopsError("Snapshot with name {0} already exists"
                                  .format(name))

        # Check that existing snapshot has the same type
        self._assert_snapshot_type(external=external)

        local_disk_devices = []
        if external:
            # EXTERNAL SNAPSHOTS
            if self.driver.get_libvirt_version() < 1002012:
                raise DevopsError(
                    "For external snapshots we need libvirtd >= 1.2.12")

            # Check whether we have directory for snapshots, if not
            # create it
            if not os.path.exists(settings.SNAPSHOTS_EXTERNAL_DIR):
                os.makedirs(settings.SNAPSHOTS_EXTERNAL_DIR)

            # create new volume which will be used as
            # disk for snapshot changes
            self.snapshot_create_child_volumes(name)

            base_memory_file = '{0}/snapshot-memory-{1}_{2}.{3}'.format(
                settings.SNAPSHOTS_EXTERNAL_DIR,
                deepgetattr(self, 'group.environment.name'),
                self.name,
                name)
            file_count = 0
            memory_file = base_memory_file
            while os.path.exists(memory_file):
                memory_file = base_memory_file + '-' + str(file_count)
                file_count += 1

            for disk in self.disk_devices:
                if disk.device == 'disk':
                    local_disk_devices.append(dict(
                        disk_volume_path=disk.volume.get_path(),
                        disk_target_dev=disk.target_dev,
                    ))

            if self.is_active() and not disk_only:
                create_xml_flag = libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT
            else:
                create_xml_flag = (
                    libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY |
                    libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT
                )

        else:
            # ORIGINAL SNAPSHOTS
            memory_file = ''
            create_xml_flag = 0

        xml = LibvirtXMLBuilder.build_snapshot_xml(
            name=name,
            description=description,
            external=external,
            disk_only=disk_only,
            memory_file=memory_file,
            domain_isactive=self.is_active(),
            local_disk_devices=local_disk_devices
        )

        domain = self._libvirt_node
        logger.info(xml)
        logger.info(domain.state(0))

        domain.snapshotCreateXML(xml, create_xml_flag)

        if external:
            self.set_snapshot_current(name)

        logger.info(domain.state(0))
    def __exec_command(cls, command, cwd=None, env=None, timeout=None,
                       verbose=False):
        """Command executor helper

        :type command: str
        :type cwd: str
        :type env: dict
        :type timeout: int
        :rtype: ExecResult
        """
        def poll_stream(src, verb_logger=None):
            dst = []
            try:
                for line in src:
                    dst.append(line)
                    if verb_logger is not None:
                        verb_logger(
                            line.decode('utf-8',
                                        errors='backslashreplace').rstrip()
                        )
            except IOError:
                pass
            return dst

        def poll_streams(result, stdout, stderr, verbose):
            rlist, _, _ = select.select(
                [stdout, stderr],
                [],
                [])
            if rlist:
                if stdout in rlist:
                    result.stdout += poll_stream(
                        src=stdout,
                        verb_logger=logger.info if verbose else logger.debug)
                if stderr in rlist:
                    result.stderr += poll_stream(
                        src=stderr,
                        verb_logger=logger.error if verbose else logger.debug)

        @decorators.threaded(started=True)
        def poll_pipes(proc, result, stop):
            """Polling task for FIFO buffers

            :type proc: subprocess.Popen
            :type result: ExecResult
            :type stop: threading.Event
            """
            # Get file descriptors for stdout and stderr streams
            fd_stdout = proc.stdout.fileno()
            fd_stderr = proc.stderr.fileno()
            # Get flags of stdout and stderr streams
            fl_stdout = fcntl.fcntl(fd_stdout, fcntl.F_GETFL)
            fl_stderr = fcntl.fcntl(fd_stderr, fcntl.F_GETFL)
            # Set nonblock mode for stdout and stderr streams
            fcntl.fcntl(fd_stdout, fcntl.F_SETFL, fl_stdout | os.O_NONBLOCK)
            fcntl.fcntl(fd_stderr, fcntl.F_SETFL, fl_stderr | os.O_NONBLOCK)

            while not stop.isSet():
                time.sleep(0.1)
                poll_streams(
                    result=result,
                    stdout=proc.stdout,
                    stderr=proc.stderr,
                    verbose=verbose
                )

                proc.poll()

                if proc.returncode is not None:
                    result.exit_code = proc.returncode
                    result.stdout += poll_stream(
                        src=proc.stdout,
                        verb_logger=logger.info if verbose else logger.debug)
                    result.stderr += poll_stream(
                        src=proc.stderr,
                        verb_logger=logger.error if verbose else logger.debug)

                    stop.set()

        # 1 Command per run
        with cls.__lock:
            result = exec_result.ExecResult(cmd=command)
            stop_event = threading.Event()
            message = log_templates.CMD_EXEC.format(cmd=command.rstrip())
            if verbose:
                logger.info(message)
            else:
                logger.debug(message)
            # Run
            process = subprocess.Popen(
                args=[command],
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                shell=True, cwd=cwd, env=env,
                universal_newlines=False)

            # Poll output
            poll_pipes(process, result, stop_event)
            # wait for process close
            stop_event.wait(timeout)

            # Process closed?
            if stop_event.isSet():
                stop_event.clear()
                return result
            # Kill not ended process and wait for close
            try:
                process.kill()  # kill -9
                stop_event.wait(5)

            except OSError:
                # Nothing to kill
                logger.warning(
                    u"{!s} has been completed just after timeout: "
                    "please validate timeout.".format(command))

            wait_err_msg = log_templates.CMD_WAIT_ERROR.format(
                cmd=command.rstrip(),
                timeout=timeout)
            output_brief_msg = ('\tSTDOUT:\n'
                                '{0}\n'
                                '\tSTDERR"\n'
                                '{1}'.format(result.stdout_brief,
                                             result.stderr_brief))
            logger.debug(wait_err_msg)
            raise error.TimeoutError(wait_err_msg + output_brief_msg)
Beispiel #43
0
    def define(self):
        """Define node

            :rtype : None
        """
        name = underscored(
            deepgetattr(self, 'group.environment.name'),
            self.name,
        )

        local_disk_devices = []
        for disk in self.disk_devices:
            local_disk_devices.append(
                dict(
                    disk_type=disk.type,
                    disk_device=disk.device,
                    disk_volume_format=disk.volume.format,
                    disk_volume_path=disk.volume.get_path(),
                    disk_bus=disk.bus,
                    disk_target_dev=disk.target_dev,
                    disk_serial=uuid.uuid4().hex,
                ))

        local_interfaces = []
        for interface in self.interfaces:
            if interface.type != 'network':
                raise NotImplementedError(
                    message='Interface types different from network are not '
                    'implemented yet')

            l2_dev = interface.l2_network_device
            local_interfaces.append(
                dict(
                    interface_type=interface.type,
                    interface_mac_address=interface.mac_address,
                    interface_network_name=l2_dev.network_name(),
                    interface_id=interface.id,
                    interface_model=interface.model,
                ))

        emulator = self.driver.get_capabilities().find(
            'guest/arch[@name="{0:>s}"]/'
            'domain[@type="{1:>s}"]/emulator'.format(self.architecture,
                                                     self.hypervisor)).text
        node_xml = LibvirtXMLBuilder.build_node_xml(
            name=name,
            hypervisor=self.hypervisor,
            use_host_cpu=self.driver.use_host_cpu,
            vcpu=self.vcpu,
            memory=self.memory,
            use_hugepages=self.driver.use_hugepages,
            hpet=self.driver.hpet,
            os_type=self.os_type,
            architecture=self.architecture,
            boot=self.boot,
            reboot_timeout=self.driver.reboot_timeout,
            bootmenu_timeout=self.bootmenu_timeout,
            emulator=emulator,
            has_vnc=self.has_vnc,
            vnc_password=self.driver.vnc_password,
            local_disk_devices=local_disk_devices,
            interfaces=local_interfaces,
        )
        logger.info(node_xml)
        self.uuid = self.driver.conn.defineXML(node_xml).UUIDString()

        super(Node, self).define()
Beispiel #44
0
    def snapshot(self,
                 name=None,
                 force=False,
                 description=None,
                 disk_only=False,
                 external=False):

        # Erase existing snapshot or raise an error if already exists
        if self.has_snapshot(name):
            if force:
                self.erase_snapshot(name)
            else:
                raise DevopsError(
                    "Snapshot with name {0} already exists".format(name))

        # Check that existing snapshot has the same type
        self._assert_snapshot_type(external=external)

        local_disk_devices = []
        if external:
            # EXTERNAL SNAPSHOTS
            if self.driver.get_libvirt_version() < 1002012:
                raise DevopsError(
                    "For external snapshots we need libvirtd >= 1.2.12")

            # Check whether we have directory for snapshots, if not
            # create it
            if not os.path.exists(settings.SNAPSHOTS_EXTERNAL_DIR):
                os.makedirs(settings.SNAPSHOTS_EXTERNAL_DIR)

            # create new volume which will be used as
            # disk for snapshot changes
            self.snapshot_create_child_volumes(name)

            base_memory_file = '{0}/snapshot-memory-{1}_{2}.{3}'.format(
                settings.SNAPSHOTS_EXTERNAL_DIR,
                deepgetattr(self, 'group.environment.name'), self.name, name)
            file_count = 0
            memory_file = base_memory_file
            while os.path.exists(memory_file):
                memory_file = base_memory_file + '-' + str(file_count)
                file_count += 1

            for disk in self.disk_devices:
                if disk.device == 'disk':
                    local_disk_devices.append(
                        dict(
                            disk_volume_path=disk.volume.get_path(),
                            disk_target_dev=disk.target_dev,
                        ))

            if self.is_active() and not disk_only:
                create_xml_flag = libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT
            else:
                create_xml_flag = (
                    libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY
                    | libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT)

        else:
            # ORIGINAL SNAPSHOTS
            memory_file = ''
            create_xml_flag = 0

        xml = LibvirtXMLBuilder.build_snapshot_xml(
            name=name,
            description=description,
            external=external,
            disk_only=disk_only,
            memory_file=memory_file,
            domain_isactive=self.is_active(),
            local_disk_devices=local_disk_devices)

        domain = self._libvirt_node
        logger.info(xml)
        logger.info(domain.state(0))

        domain.snapshotCreateXML(xml, create_xml_flag)

        if external:
            self.set_snapshot_current(name)

        logger.info(domain.state(0))
Beispiel #45
0
    def __exec_command(
            cls, command, channel, stdout, stderr, timeout, verbose=False):
        """Get exit status from channel with timeout

        :type command: str
        :type channel: paramiko.channel.Channel
        :type stdout: paramiko.channel.ChannelFile
        :type stderr: paramiko.channel.ChannelFile
        :type timeout: int
        :type verbose: bool
        :rtype: ExecResult
        :raises: TimeoutError
        """
        def poll_stream(src, verb_logger=None):
            dst = []
            try:
                for line in src:
                    dst.append(line)
                    if verb_logger is not None:
                        verb_logger(
                            line.decode('utf-8',
                                        errors='backslashreplace').rstrip()
                        )
            except IOError:
                pass
            return dst

        def poll_streams(result, channel, stdout, stderr, verbose):
            if channel.recv_ready():
                result.stdout += poll_stream(
                    src=stdout,
                    verb_logger=logger.info if verbose else logger.debug)
            if channel.recv_stderr_ready():
                result.stderr += poll_stream(
                    src=stderr,
                    verb_logger=logger.error if verbose else logger.debug)

        @decorators.threaded(started=True)
        def poll_pipes(stdout, stderr, result, stop, channel):
            """Polling task for FIFO buffers

            :type stdout: paramiko.channel.ChannelFile
            :type stderr: paramiko.channel.ChannelFile
            :type result: ExecResult
            :type stop: Event
            :type channel: paramiko.channel.Channel
            """

            while not stop.isSet():
                time.sleep(0.1)
                poll_streams(
                    result=result,
                    channel=channel,
                    stdout=stdout,
                    stderr=stderr,
                    verbose=verbose
                )

                if channel.status_event.is_set():
                    result.exit_code = result.exit_code = channel.exit_status

                    result.stdout += poll_stream(
                        src=stdout,
                        verb_logger=logger.info if verbose else logger.debug)
                    result.stderr += poll_stream(
                        src=stderr,
                        verb_logger=logger.error if verbose else logger.debug)

                    stop.set()

        # channel.status_event.wait(timeout)
        result = exec_result.ExecResult(cmd=command)
        stop_event = threading.Event()
        message = log_templates.CMD_EXEC.format(cmd=command.rstrip())
        if verbose:
            logger.info(message)
        else:
            logger.debug(message)

        poll_pipes(
            stdout=stdout,
            stderr=stderr,
            result=result,
            stop=stop_event,
            channel=channel
        )

        stop_event.wait(timeout)

        # Process closed?
        if stop_event.isSet():
            stop_event.clear()
            channel.close()
            return result

        stop_event.set()
        channel.close()
        wait_err_msg = log_templates.CMD_WAIT_ERROR.format(
            cmd=command.rstrip(),
            timeout=timeout)
        output_brief_msg = ('\tSTDOUT:\n'
                            '{0}\n'
                            '\tSTDERR"\n'
                            '{1}'.format(result.stdout_brief,
                                         result.stderr_brief))
        logger.debug(wait_err_msg)
        raise error.TimeoutError(wait_err_msg + output_brief_msg)
Beispiel #46
0
    def revert(self, name=None, destroy=True):
        """Method to revert node in state from snapshot

           For external snapshots in libvirt we use restore function.
           After reverting in this way we get situation when node is connected
           to original volume disk, without snapshot point. To solve this
           problem we need to switch it to correct volume.

           In case of usage external snapshots we clean snapshot disk when
           revert to snapshot without childs and create new snapshot point
           when reverting to snapshots with childs.
        """
        if destroy:
            self.destroy(verbose=False)
        if self.has_snapshot(name):
            snapshot = self.driver.node_get_snapshot(self, name)
            if snapshot.get_type == "external":
                self.destroy()
                if snapshot.children_num == 0:
                    logger.info("Reuse last snapshot")

                    # Update current node disks
                    self._update_disks_from_snapshot(name)

                    # Recreate volumes for snapshot and reuse it.
                    self.driver.node_revert_snapshot_recreate_disks(self, name)

                    # Revert snapshot
                    self.driver.node_revert_snapshot(node=self, name=name)
                else:
                    # Looking for last reverted snapshot without children
                    # or create new and start next snapshot chain
                    revert_name = name + "-revert"
                    revert_count = 0
                    create_new = True

                    while self.has_snapshot(revert_name):
                        # Check wheter revert snapshot has children
                        snapshot_revert = self.driver.node_get_snapshot(self, revert_name)
                        if snapshot_revert.children_num == 0:
                            logger.info("Revert snapshot exists, clean and reuse it")

                            # Update current node disks
                            self._update_disks_from_snapshot(revert_name)

                            # Recreate volumes
                            self.driver.node_revert_snapshot_recreate_disks(self, revert_name)

                            # Revert snapshot
                            self.driver.node_revert_snapshot(node=self, name=revert_name)
                            create_new = False
                            break
                        else:
                            revert_name = name + "-revert" + str(revert_count)
                            revert_count += 1

                    if create_new:
                        logger.info("Create new revert snapshot")

                        # Update current node disks
                        self._update_disks_from_snapshot(name)

                        # Revert snapshot
                        self.driver.node_revert_snapshot(node=self, name=name)

                        # Create new snapshot
                        self.snapshot(name=revert_name, external=True)
            else:
                self.driver.node_revert_snapshot(node=self, name=name)
        else:
            print(
                "Domain snapshot for {0} node not found: no domain "
                "snapshot with matching"
                " name {1}".format(self.name, name)
            )
    def __exec_command(cls,
                       command,
                       channel,
                       stdout,
                       stderr,
                       timeout,
                       verbose=False):
        """Get exit status from channel with timeout

        :type command: str
        :type channel: paramiko.channel.Channel
        :type stdout: paramiko.channel.ChannelFile
        :type stderr: paramiko.channel.ChannelFile
        :type timeout: int
        :type verbose: bool
        :rtype: ExecResult
        :raises: TimeoutError
        """
        def poll_stream(src, verb_logger=None):
            dst = []
            try:
                for line in src:
                    dst.append(line)
                    if verb_logger is not None:
                        verb_logger(
                            line.decode('utf-8',
                                        errors='backslashreplace').rstrip())
            except IOError:
                pass
            return dst

        def poll_streams(result, channel, stdout, stderr, verbose):
            if channel.recv_ready():
                result.stdout += poll_stream(
                    src=stdout,
                    verb_logger=logger.info if verbose else logger.debug)
            if channel.recv_stderr_ready():
                result.stderr += poll_stream(
                    src=stderr,
                    verb_logger=logger.error if verbose else logger.debug)

        @decorators.threaded(started=True)
        def poll_pipes(stdout, stderr, result, stop, channel):
            """Polling task for FIFO buffers

            :type stdout: paramiko.channel.ChannelFile
            :type stderr: paramiko.channel.ChannelFile
            :type result: ExecResult
            :type stop: Event
            :type channel: paramiko.channel.Channel
            """

            while not stop.isSet():
                time.sleep(0.1)
                poll_streams(result=result,
                             channel=channel,
                             stdout=stdout,
                             stderr=stderr,
                             verbose=verbose)

                if channel.status_event.is_set():
                    result.exit_code = result.exit_code = channel.exit_status

                    result.stdout += poll_stream(
                        src=stdout,
                        verb_logger=logger.info if verbose else logger.debug)
                    result.stderr += poll_stream(
                        src=stderr,
                        verb_logger=logger.error if verbose else logger.debug)

                    stop.set()

        # channel.status_event.wait(timeout)
        result = exec_result.ExecResult(cmd=command)
        stop_event = threading.Event()
        if verbose:
            logger.info("\nExecuting command: {!r}".format(command.rstrip()))
        else:
            logger.debug("\nExecuting command: {!r}".format(command.rstrip()))
        poll_pipes(stdout=stdout,
                   stderr=stderr,
                   result=result,
                   stop=stop_event,
                   channel=channel)

        stop_event.wait(timeout)

        # Process closed?
        if stop_event.isSet():
            stop_event.clear()
            channel.close()
            return result

        stop_event.set()
        channel.close()

        wait_err_msg = ('Wait for {0!r} during {1}s: no return code!\n'.format(
            command, timeout))
        output_brief_msg = ('\tSTDOUT:\n'
                            '{0}\n'
                            '\tSTDERR"\n'
                            '{1}'.format(result.stdout_brief,
                                         result.stderr_brief))
        logger.debug(wait_err_msg)
        raise error.TimeoutError(wait_err_msg + output_brief_msg)