Ejemplo n.º 1
0
class VmWareVM(VM):
    vmhost = None
    vminstance = None
            
    def __init__(self, host, bundle_dir, sb_cfg):
        VM.__init__(self, host, bundle_dir, sb_cfg)
        self.machinecfg = VmwareMachineConfig(sb_cfg, 'Machine')
        self.vmwarecfg = VmwareConfig(sb_cfg, 'Tester')
        self.asscfg = AssignmentConfig(config = sb_cfg)
        self.testercfg = TesterConfig(config = sb_cfg)
        self.vmx_path = self.machinecfg.get_vmx_path()
        if self.vmx_path == None:
            self.vmx_path = self.get_submission_vmx_file()
        if self.vmx_path == None:
            # no vmx, nothing to do.
            _logger.error('Could not find a vmx to run')
            with open(self.error_fname, 'a') as handler:
                print >> handler, 'Error powering on the virtual machine.\n' + \
                                  'Unable to find .vmx file.\n'
            sys.exit(1)

        vmx_prefix = self.testercfg.vm_store_path('Tester')
        if vmx_prefix is not None:
            self.vmx_path = os.path.join(vmx_prefix, self.vmx_path)

        try:
            if self.vmwarecfg.vmware_type() == 3:
                self.vmhost = pyvix.vix.Host()
            elif self.vmwarecfg.vmware_type() == 2 or \
                    self.vmwarecfg.vmware_type() == 10:
                self.vmhost = pyvix.vix.Host(self.vmwarecfg.vmware_type(),
                                  self.vmwarecfg.vmware_url(),
                                  int(self.vmwarecfg.vmware_port()),
                                  self.vmwarecfg.vmware_username(),
                                  self.vmwarecfg.vmware_password())
        except pyvix.vix.VIXException:
            _logger.exception('Exception thrown: ' + type(e).__name__ + "\n" + ", ".join(e.args) + "\n" + e.__str__())
            with open(self.error_fname, 'a') as handler:
                print >> handler, 'Error powering on the virtual machine.\n' + \
                                  'Connecting to the host Vmware services failed.\n'
            sys.exit(1)

        if self.vmwarecfg.vmware_register_and_unregister():
            self.vmhost.registerVM(self.vmwarecfg.vmware_rel_vmx_path(self.vmx_path))

        vmx_path = self.vmx_path
        if not os.path.isfile(vmx_path):
            vmx_path = self.vmwarecfg.vmware_rel_vmx_path(self.vmx_path)

        if not os.path.isfile(vmx_path):
            # no vmx, nothing to do.
            _logger.error('Could not find a vmx to run')
            with open(self.error_fname, 'a') as handler:
                print >> handler, 'Error powering on the virtual machine.\n' + \
                                  'Unable to find .vmx file.\n'
            sys.exit(1)

        try:
            self.vminstance = self.vmhost.openVM(vmx_path)
        except pyvix.vix.VIXException:
            _logger.exception('Exception thrown: ' + type(e).__name__ + "\n" + ", ".join(e.args) + "\n" + e.__str__())
            with open(self.error_fname, 'a') as handler:
                print >> handler, 'Error powering on the virtual machine.\n' + \
                                  'Unable to open the .vmx file..\n'
            sys.exit(1)



    def executeCommand(self,cmd):
        return self.vminstance.runProgramInGuest(self.shell,'--login -c "'+cmd+'"')
    
    def start(self):
        self.vminstance.powerOn()

    def stop(self):
        try:
            self.vminstance.powerOff()
        except pyvix.vix.VIXException:
            _logger.exception('Exception thrown: ' + type(e).__name__ + "\n" + ", ".join(e.args) + "\n" + e.__str__())
        if self.vmwarecfg.vmware_register_and_unregister():
            try:
                self.vmhost.unregisterVM(self.vmwarecfg.vmware_rel_vmx_path(self.vmx_path))
            except pyvix.vix.VIXException:
                _logger.exception('Exception thrown: ' + type(e).__name__ + "\n" + ", ".join(e.args) + "\n" + e.__str__())

    def _wait_for_tools(self):
        """Called by the thread that waits for the VMWare Tools to
           start. If the Tools do not start, there is no direct way of
           ending the Thread.  As a result, on powerOff(), the Thread
           would throw a VIXException on account of the VM not being
           powered on.
        """
        try:
            self.vminstance.waitForToolsInGuest()
        except pyvix.vix.VIXException:
            _logger.exception('Exception thrown: ' + type(e).__name__ + "\n" + ", ".join(e.args) + "\n" + e.__str__())


    def wait_for_tools_with_timeout(self, timeout, error_fname):
        """Wait for VMWare Tools to start.

        Returns True on success and False when the VMWare tools did not
        start properly in the given timeout. Writes error messages to
        `error_fname`.
        """

        if timeout > 0:
            _logger.info('Waiting for VMWare Tools with a timeout of %d seconds' % timeout)

        tools_thd = Thread(target = self._wait_for_tools)
        tools_thd.start()
        # normally the thread will end before the timeout expires, so a high timeout
        tools_thd.join(timeout)


        if not tools_thd.isAlive():
            return True


        _logger.error('Timeout waiting for VMWare Tools to start.' +
                      'Make sure your virtual machine boots up corectly' +
                      'and that you have VMWare Tools installed.')

        with open(error_fname, 'a') as handler:
            print >> handler, 'Timeout waiting for VMWare Tools to start.\n' + \
                      'Make sure your virtual machine boots up corectly\n' + \
                      'and that you have VMWare Tools installed.\n'
        return False

    def powerOn(self):
        """ see power_on_with_message_handler """
        power_thd = Thread(target = self.start)
        power_thd.start()

        if self.vmwarecfg.vmware_type() == 2 or \
                self.vmwarecfg.vmware_type() == 10:
            # VMWARE_SERVER or VMWARE_VI_SERVER
            # Wait for the VM to powr on in case it hangs on a message
            power_thd.join(VMWARE_VM_POWERON_TIMEOUT)

            if not power_thd.isAlive():
                # vm.powerOn() didn't hang: the machine has been powered on
                return

            # Run the message handler
            proc = Popen(['vmchecker-message-handler',
                      self.vmwarecfg.vmware_hostname(),
                      self.vmwarecfg.vmware_username(),
                      self.vmwarecfg.vmware_password(),
                      self.vmwarecfg.vmware_rel_vmx_path(self.vmx_path)])
            os.waitpid(proc.pid, 0)

            # Wait for the VM to power on again
            power_thd.join(VMWARE_VM_POWERON_TIMEOUT)

            if not power_thd.isAlive():
                # vm.powerOn() didn't hang: the machine has been powered on
                return

            _logger.error('Powering on VM timed out')
            with open(self.error_fname, 'a') as handler:
                print >> handler, 'Error powering on the virtual machine.\n' + \
                                  'Timed out while powering on.\n'
            sys.exit(1)
        else:
            # VMWARE_WORKSTATION
            # Just wait until the VM has powered on
            power_thd.join()

    def try_power_on_vm_and_login(self, revertSnapshot=None):
        if revertSnapshot == True or \
           (revertSnapshot == None and self.asscfg.revert_to_snapshot('Assignment')):
            self.revert(self.vminstance.nRootSnapshots - 1)

        tools_timeout = self.asscfg.delay_wait_for_tools('Assignment')
        self.powerOn()
        
        if not self.wait_for_tools_with_timeout(tools_timeout, self.error_fname):
            # no tools, nothing to do.
            return False

        try:
            self.vminstance.loginInGuest(self.machinecfg.guest_user(), self.machinecfg.guest_pass())
        except pyvix.vix.VIXSecurityException:
            _logger.error('Error logging in on the virtual machine.' +
                          'Make sure you have the accounts properly configured.')
            with open(error_fname, 'a') as handler:
                print >> handler,'Error logging in on the virtual machine.\n' + \
                        'Make sure you have the user accounts properly configured.\n'
                return False

        time.sleep(self.asscfg.delay_between_tools_and_tests('Assignment'))
        return True
        
        
    def revert(self, number = None):
        """Revert the vminstance to the number snapshot

        Note: snapshots are counted from 0.
        """
        if number==None:
            _logger.error('Snapshot number is needed')
            return
        if self.vminstance.nRootSnapshots <= number:
            err_str = ('Cannot revert to snapshot %d. Too few ' +
                       'snapshots (nr = %d) found on %s.' %
                       (number, self.vminstance.nRootSnapshots, self.vminstance.vmxPath))
            raise Exception(err_str)
        snaps = self.vminstance.rootSnapshots
	try:
	        self.vminstance.revertToSnapshot(snaps[number])
	except:
	        _logger.error('Could not revert to snapshot')
       
    def copyTo(self, sourceDir, targetDir, files):
        """ Copy files from host(source) to guest(target) """
        for f in files:
            host_path = os.path.join(sourceDir, f)
            guest_path = targetDir + f
            if not os.path.exists(host_path):
                _logger.error('host file (to send) "%s" does not exist' % host_path)
                return
            _logger.info('copy file %s from host to guest at %s' % (host_path, guest_path))
            self.vminstance.copyFileFromHostToGuest(host_path, guest_path)
        
    def copyFrom(self, sourceDir, targetDir, files):
        """ Copy files from guest(source) to host(target) """
        for f in files:
            host_path = os.path.join(targetDir, f)
            guest_path = sourceDir + f
            _logger.info('copy file %s from guest to host at %s' % (guest_path, host_path))
            self.vminstance.copyFileFromGuestToHost(guest_path, host_path)
            if not os.path.exists(host_path):
                _logger.error('host file (received) "%s" does not exist' % host_path)

    def run(self, shell, executable_file, timeout):
        args = ' --login -c ' + '"chmod +x ' + executable_file + '; ' + executable_file + '"'
        self.executeCommand("chmod +x "+ executable_file)
        _logger.info('executing on the remote: prog=%s args=[%s] timeout=%d' % (shell, executable_file, timeout))
        thd = Thread(target = self.vminstance.runProgramInGuest, args = (shell,args))
        thd.start()
        thd.join(timeout)
        return thd.isAlive()
        
    def get_submission_vmx_file(self):
        """Unzip search the bundle_dir and locate the .vmx file, no matter
        in what sub-folders it is located in. If the unzipped archive has
        multiple .vmx files, just pick the first.

        """
        for (root, _, files) in os.walk(self.bundle_dir):
            for f in files:
                if f.endswith(".vmx"):
                    return os.path.join(root, f)
        return None

    def hasStarted(self):
        return self.vminstance[VIX_PROPERTY_VM_POWER_STATE] & VIX_POWERSTATE_TOOLS_RUNNING != 0

    def hasStopped(self):
        return self.vminstance[VIX_PROPERTY_VM_POWER_STATE] & VIX_POWERSTATE_POWERED_OFF != 0
Ejemplo n.º 2
0
class OneVM(VM):
    # this module works with the assumtipon that there is a snapshot that we can use
    # start means resume to snapshot
    # stop means resume to snapshot
    # resume means resume (but) it should not be used from outside
    # start and stop operations are blocking (i.e. we wait for the machine to
    # be up again)
    def __init__(self, host, bundle_dir, sb_cfg):
        VM.__init__(self, host, bundle_dir, sb_cfg)
        self.machinecfg = OneMachineConfig(sb_cfg, 'Machine')
        self.asscfg = AssignmentConfig(sb_cfg)
        self.one_server = self.machinecfg.get_one_server()
        self.one_credentials = self.machinecfg.get_one_credentials()

        self.vm_id = int(self.machinecfg.get_one_vm_id())
        self.one_vm_hostname = self.machinecfg.get_one_vm_hostname()
        self.vm_username = self.machinecfg.guest_user()
        self.snapshot_id = 0

        # we cannot use the revert mechanism from outside
        assert(False == self.asscfg.revert_to_snapshot('Assignment'))

    def start(self):
        # assume that the vm has been already suspended in a good state
        _logger.info("starting vm %d" % self.vm_id)
        self.revert(self.snapshot_id)
        while not self.hasStarted():
            time.sleep(1)
            _logger.info("start wait for %d" % self.vm_id)

    def stop(self):
        # cleanup the work (do not suspend)
        _logger.info("stopping vm %d" % self.vm_id)
        self.revert(self.snapshot_id)
        while not self.hasStarted():
            time.sleep(1)
            _logger.info("stop wait for %d" % self.vm_id)

    def hasStarted(self):
        state, state_ext = self._get_state()
        if state == 3 and state_ext == 3:
            return True
        return False

    def executeCommand(self, cmd):
        _logger.debug("execute on vm %d: %s" % \
                (self.vm_id, cmd))

        client = self._create_ssh_connection()

        try:
            # this doesn't waits for the commands (I think)
            stdin, stdout, stderr = client.exec_command(cmd)
            stdin.close()
            stdout.close()
            stderr.close()
        finally:
            client.close()

    def revert(self, number = None):
        if not number:
            number = self.snapshot_id
        _logger.info("doing revert to snapshot id %d" % number)

        REVERT_TIMEOUT = 300
        cnt = 0
        while not self.hasStarted() and cnt < REVERT_TIMEOUT:
            cnt += 1
            time.sleep(1)
            _logger.info("revert wait for %d" % self.vm_id)

        if cnt == REVERT_TIMEOUT:
            _logger.warning("probably failing")

        self._rpc('one.vm.snapshotrevert', self.vm_id, number)

    def copyTo(self, sourceDir, targetDir, files):
        _logger.info("copy to vm %d, %s->%s (%s)" % \
                (self.vm_id, sourceDir, targetDir, files))

        t, sftp = self._create_sftp_connection_to_vm()
        try:
            for f in files:
                src_f = os.path.join(sourceDir, f)
                # assume remote path delim == host path delim
                dst_f = os.path.join(targetDir, f)
                sftp.put(src_f, dst_f, confirm=True)
        finally:
            t.close()

    def copyFrom(self, sourceDir, targetDir, files):
        _logger.info("copy from vm %d, %s->%s (%s)" % \
                (self.vm_id, sourceDir, targetDir, files))

        t, sftp = self._create_sftp_connection_to_vm()
        try:
            for f in files:
                src_f = os.path.join(sourceDir, f)
                # assume remote path delim == host path delim
                dst_f = os.path.join(targetDir, f)
                sftp.get(src_f, dst_f)
        finally:
            t.close()

    def run(self, shell, executable_file, timeout):
        _logger.info("run on vm %d: %s %s" % \
                (self.vm_id, shell, executable_file))

        cmd = shell+' '+executable_file+' '+str(timeout)

        client = self._create_ssh_connection()
        try:
            stdin, stdout, stderr = client.exec_command(cmd)

            while timeout > 0 and not stdout.channel.exit_status_ready():
                time.sleep(1)
                timeout -= 1
                _logger.debug('wait for cmd to finish: [%s]' % cmd)

            stdin.close()
            stdout.close()
            stderr.close()
        finally:
            client.close()

    def _create_ssh_connection(self):
        client = paramiko.SSHClient()
        try:
            # XXX: we should use a more strict policy
            client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            client.connect(self.one_vm_hostname,
                    username=self.vm_username)
        except:
            client.close()
            raise
        return client

    def _create_sftp_connection_to_vm(self):
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        ip = socket.gethostbyname(self.one_vm_hostname)
        sock.connect((ip, 22))
        t = paramiko.Transport(sock)
        try:
            t.start_client()
            sftp = None

            key = paramiko.RSAKey.from_private_key_file(\
                        os.path.join(os.environ['HOME'], '.ssh/id_rsa'))
            t.auth_publickey(self.vm_username, key)
            sftp = paramiko.SFTPClient.from_transport(t)
        except:
            t.close()
            t = None
            sftp = None
            raise

        return (t, sftp)

    def _get_state(self):
          # http://docs.opennebula.org/4.4/integration/system_interfaces/api.html#one-vm-info
          # INIT      = 0
          # PENDING   = 1
          # HOLD      = 2
          # ACTIVE    = 3
          # STOPPED   = 4
          # SUSPENDED = 5
          # DONE      = 6
          # FAILED    = 7
          # POWEROFF  = 8
          # UNDEPLOYED = 9

          #LCM_INIT            = 0,
          #PROLOG              = 1,
          #BOOT                = 2,
          #RUNNING             = 3,
          #MIGRATE             = 4,
          #SAVE_STOP           = 5,
          #SAVE_SUSPEND        = 6,
          #SAVE_MIGRATE        = 7,
          #PROLOG_MIGRATE      = 8,
          #PROLOG_RESUME       = 9,
          #EPILOG_STOP         = 10,
          #EPILOG              = 11,
          #SHUTDOWN            = 12,
          #CANCEL              = 13,
          #FAILURE             = 14,
          #CLEANUP_RESUBMIT    = 15,
          #UNKNOWN             = 16,
          #HOTPLUG             = 17,
          #SHUTDOWN_POWEROFF   = 18,
          #BOOT_UNKNOWN        = 19,
          #BOOT_POWEROFF       = 20,
          #BOOT_SUSPENDED      = 21,
          #BOOT_STOPPED        = 22,
          #CLEANUP_DELETE      = 23,
          #HOTPLUG_SNAPSHOT    = 24,
          #HOTPLUG_NIC         = 25,
          #HOTPLUG_SAVEAS           = 26,
          #HOTPLUG_SAVEAS_POWEROFF  = 27,
          #HOTPLUG_SAVEAS_SUSPENDED = 28,
          #SHUTDOWN_UNDEPLOY   = 29,
          #EPILOG_UNDEPLOY     = 30,
          #PROLOG_UNDEPLOY     = 31,
          #BOOT_UNDEPLOY       = 32

        _, info, _ = self._rpc('one.vm.info', self.vm_id)
        xmldoc = minidom.parseString(info)
        state = int(xmldoc.getElementsByTagName('STATE')[0].firstChild.nodeValue)
        state_ext = int(xmldoc.getElementsByTagName('LCM_STATE')[0].firstChild.nodeValue)
        if state != 3:
            state_ext = None

        _logger.debug("state form vm %d is (%s:%s)" % (self.vm_id, state, state_ext))
        return (state, state_ext)

    def _get_proxy(self):
        return xmlrpclib.ServerProxy(self.one_server)

    def _rpc(self, *kargs):
        p = self._get_proxy()
        method = getattr(p, kargs[0])
        ret = method(self.one_credentials, *kargs[1:])
        #_logger.debug("%s" % str(ret))
        if not ret[0]:
            raise OneVMException("One RPC: %s" % ret[1])
        return ret
Ejemplo n.º 3
0
class VmWareVM(VM):
    vmhost = None
    vminstance = None
            
    def __init__(self, host, bundle_dir, sb_cfg):
        VM.__init__(self, host, bundle_dir, sb_cfg)
        self.machinecfg = VmwareMachineConfig(sb_cfg, 'Machine')
        self.vmwarecfg = VmwareConfig(sb_cfg, 'Tester')
        self.asscfg = AssignmentConfig(config = sb_cfg)
        self.testercfg = TesterConfig(config = sb_cfg)
        self.vmx_path = self.machinecfg.get_vmx_path()
        if self.vmx_path == None:
            self.vmx_path = self.get_submission_vmx_file()
        if self.vmx_path == None:
            # no vmx, nothing to do.
            _logger.error('Could not find a vmx to run')
            with open(self.error_fname, 'a') as handler:
                print >> handler, 'Error powering on the virtual machine.\n' + \
                                  'Unable to find .vmx file.\n'
            sys.exit(1)

        vmx_prefix = self.testercfg.vm_store_path('Tester')
        if vmx_prefix is not None:
            self.vmx_path = os.path.join(vmx_prefix, self.vmx_path)

        try:
            if self.vmwarecfg.vmware_type() == 3:
                self.vmhost = pyvix.vix.Host()
            elif self.vmwarecfg.vmware_type() == 2 or \
                    self.vmwarecfg.vmware_type() == 10:
                self.vmhost = pyvix.vix.Host(self.vmwarecfg.vmware_type(),
                                  self.vmwarecfg.vmware_url(),
                                  int(self.vmwarecfg.vmware_port()),
                                  self.vmwarecfg.vmware_username(),
                                  self.vmwarecfg.vmware_password())
        except pyvix.vix.VIXException as e:
            _logger.exception('Exception thrown: ' + type(e).__name__ + "\n" + ", ".join(e.args) + "\n" + e.__str__())
            with open(self.error_fname, 'a') as handler:
                print >> handler, 'Error powering on the virtual machine.\n' + \
                                  'Connecting to the host Vmware services failed.\n'
            sys.exit(1)

        if self.vmwarecfg.vmware_register_and_unregister():
            self.vmhost.registerVM(self.vmwarecfg.vmware_rel_vmx_path(self.vmx_path))

        vmx_path = self.vmx_path
        if not os.path.isfile(vmx_path):
            vmx_path = self.vmwarecfg.vmware_rel_vmx_path(self.vmx_path)

        if not os.path.isfile(vmx_path):
            # no vmx, nothing to do.
            _logger.error('Could not find a vmx to run')
            with open(self.error_fname, 'a') as handler:
                print >> handler, 'Error powering on the virtual machine.\n' + \
                                  'Unable to find .vmx file.\n'
            sys.exit(1)

        try:
            self.vminstance = self.vmhost.openVM(vmx_path)
        except pyvix.vix.VIXException as e:
            _logger.exception('Exception thrown: ' + type(e).__name__ + "\n" + ", ".join(e.args) + "\n" + e.__str__())
            with open(self.error_fname, 'a') as handler:
                print >> handler, 'Error powering on the virtual machine.\n' + \
                                  'Unable to open the .vmx file..\n'
            sys.exit(1)



    def executeCommand(self,cmd):
        return self.vminstance.runProgramInGuest(self.shell,'--login -c "'+cmd+'"')
    
    def start(self):
        self.vminstance.powerOn()

    def stop(self):
        try:
            self.vminstance.powerOff()
        except pyvix.vix.VIXException as e:
            _logger.exception('Exception thrown: ' + type(e).__name__ + "\n" + ", ".join(e.args) + "\n" + e.__str__())
        if self.vmwarecfg.vmware_register_and_unregister():
            try:
                self.vmhost.unregisterVM(self.vmwarecfg.vmware_rel_vmx_path(self.vmx_path))
            except pyvix.vix.VIXException as e:
                _logger.exception('Exception thrown: ' + type(e).__name__ + "\n" + ", ".join(e.args) + "\n" + e.__str__())

    def _wait_for_tools(self):
        """Called by the thread that waits for the VMWare Tools to
           start. If the Tools do not start, there is no direct way of
           ending the Thread.  As a result, on powerOff(), the Thread
           would throw a VIXException on account of the VM not being
           powered on.
        """
        try:
            self.vminstance.waitForToolsInGuest()
        except pyvix.vix.VIXException as e:
            _logger.exception('Exception thrown: ' + type(e).__name__ + "\n" + ", ".join(e.args) + "\n" + e.__str__())


    def wait_for_tools_with_timeout(self, timeout, error_fname):
        """Wait for VMWare Tools to start.

        Returns True on success and False when the VMWare tools did not
        start properly in the given timeout. Writes error messages to
        `error_fname`.
        """

        if timeout > 0:
            _logger.info('Waiting for VMWare Tools with a timeout of %d seconds' % timeout)

        tools_thd = Thread(target = self._wait_for_tools)
        tools_thd.start()
        # normally the thread will end before the timeout expires, so a high timeout
        tools_thd.join(timeout)


        if not tools_thd.isAlive():
            return True


        _logger.error('Timeout waiting for VMWare Tools to start. ' +
                      'Make sure your virtual machine boots up correctly ' +
                      'and that you have VMWare Tools installed.')

        with open(error_fname, 'a') as handler:
            print >> handler, 'Timeout waiting for VMWare Tools to start.\n' + \
                      'Make sure your virtual machine boots up corectly\n' + \
                      'and that you have VMWare Tools installed.\n'
        return False

    def powerOn(self):
        """ see power_on_with_message_handler """
        power_thd = Thread(target = self.start)
        power_thd.start()

        if self.vmwarecfg.vmware_type() == 2 or \
                self.vmwarecfg.vmware_type() == 10:
            # VMWARE_SERVER or VMWARE_VI_SERVER
            # Wait for the VM to powr on in case it hangs on a message
            power_thd.join(VMWARE_VM_POWERON_TIMEOUT)

            if not power_thd.isAlive():
                # vm.powerOn() didn't hang: the machine has been powered on
                return

            # Run the message handler
            proc = Popen(['vmchecker-message-handler',
                      self.vmwarecfg.vmware_hostname(),
                      self.vmwarecfg.vmware_username(),
                      self.vmwarecfg.vmware_password(),
                      self.vmwarecfg.vmware_rel_vmx_path(self.vmx_path)])
            os.waitpid(proc.pid, 0)

            # Wait for the VM to power on again
            power_thd.join(VMWARE_VM_POWERON_TIMEOUT)

            if not power_thd.isAlive():
                # vm.powerOn() didn't hang: the machine has been powered on
                return

            _logger.error('Powering on VM timed out')
            with open(self.error_fname, 'a') as handler:
                print >> handler, 'Error powering on the virtual machine.\n' + \
                                  'Timed out while powering on.\n'
            sys.exit(1)
        else:
            # VMWARE_WORKSTATION
            # Just wait until the VM has powered on
            power_thd.join()

    def try_power_on_vm_and_login(self, revertSnapshot=None):
        if revertSnapshot == True or \
           (revertSnapshot == None and self.asscfg.revert_to_snapshot('Assignment')):
            self.revert(self.vminstance.nRootSnapshots - 1)

        tools_timeout = self.asscfg.delay_wait_for_tools('Assignment')
        self.powerOn()
        
        if not self.wait_for_tools_with_timeout(tools_timeout, self.error_fname):
            # no tools, nothing to do.
            return False

        try:
            self.vminstance.loginInGuest(self.machinecfg.guest_user(), self.machinecfg.guest_pass())
        except pyvix.vix.VIXSecurityException:
            _logger.error('Error logging in on the virtual machine.' +
                          'Make sure you have the accounts properly configured.')
            with open(error_fname, 'a') as handler:
                print >> handler,'Error logging in on the virtual machine.\n' + \
                        'Make sure you have the user accounts properly configured.\n'
                return False

        time.sleep(self.asscfg.delay_between_tools_and_tests('Assignment'))
        return True
        
        
    def revert(self, number = None):
        """Revert the vminstance to the number snapshot

        Note: snapshots are counted from 0.
        """
        if number==None:
            _logger.error('Snapshot number is needed')
            return
        if self.vminstance.nRootSnapshots <= number:
            err_str = ('Cannot revert to snapshot %d. Too few ' +
                       'snapshots (nr = %d) found on %s.' %
                       (number, self.vminstance.nRootSnapshots, self.vminstance.vmxPath))
            raise Exception(err_str)
        snaps = self.vminstance.rootSnapshots
	try:
	        self.vminstance.revertToSnapshot(snaps[number])
	except:
	        _logger.error('Could not revert to snapshot')
       
    def copyTo(self, sourceDir, targetDir, files):
        """ Copy files from host(source) to guest(target) """
        if self.vminstance[VIX_PROPERTY_VM_POWER_STATE] & VIX_POWERSTATE_TOOLS_RUNNING == 0:
            return
        for f in files:
            host_path = os.path.join(sourceDir, f)
            guest_path = targetDir + f
            if not os.path.exists(host_path):
                _logger.error('host file (to send) "%s" does not exist' % host_path)
                return
            _logger.info('copy file %s from host to guest at %s' % (host_path, guest_path))
            self.vminstance.copyFileFromHostToGuest(host_path, guest_path)
        
    def copyFrom(self, sourceDir, targetDir, files):
        """ Copy files from guest(source) to host(target) """
        if self.vminstance[VIX_PROPERTY_VM_POWER_STATE] & VIX_POWERSTATE_TOOLS_RUNNING == 0:
            return
        for f in files:
            host_path = os.path.join(targetDir, f)
            guest_path = sourceDir + f
            _logger.info('copy file %s from guest to host at %s' % (guest_path, host_path))
            self.vminstance.copyFileFromGuestToHost(guest_path, host_path)
            if not os.path.exists(host_path):
                _logger.error('host file (received) "%s" does not exist' % host_path)

    def run(self, shell, executable_file, timeout):
        args = ' --login -c ' + '"chmod +x ' + executable_file + '; ' + executable_file + '"'
        self.executeCommand("chmod +x "+ executable_file)
        _logger.info('executing on the remote: prog=%s args=[%s] timeout=%d' % (shell, executable_file, timeout))
        thd = Thread(target = self.vminstance.runProgramInGuest, args = (shell,args))
        thd.start()
        thd.join(timeout)
        return thd.isAlive()
        
    def get_submission_vmx_file(self):
        """Unzip search the bundle_dir and locate the .vmx file, no matter
        in what sub-folders it is located in. If the unzipped archive has
        multiple .vmx files, just pick the first.

        """
        for (root, _, files) in os.walk(self.bundle_dir):
            for f in files:
                if f.endswith(".vmx"):
                    return os.path.join(root, f)
        return None

    def hasStarted(self):
        return self.vminstance[VIX_PROPERTY_VM_POWER_STATE] & VIX_POWERSTATE_TOOLS_RUNNING != 0

    def hasStopped(self):
        return self.vminstance[VIX_PROPERTY_VM_POWER_STATE] & VIX_POWERSTATE_POWERED_OFF != 0
Ejemplo n.º 4
0
class OneVM(VM):
    # this module works with the assumtipon that there is a snapshot that we can use
    # start means resume to snapshot
    # stop means resume to snapshot
    # resume means resume (but) it should not be used from outside
    # start and stop operations are blocking (i.e. we wait for the machine to
    # be up again)
    def __init__(self, host, bundle_dir, sb_cfg):
        VM.__init__(self, host, bundle_dir, sb_cfg)
        self.machinecfg = OneMachineConfig(sb_cfg, 'Machine')
        self.asscfg = AssignmentConfig(sb_cfg)
        self.one_server = self.machinecfg.get_one_server()
        self.one_credentials = self.machinecfg.get_one_credentials()

        self.vm_id = int(self.machinecfg.get_one_vm_id())
        self.one_vm_hostname = self.machinecfg.get_one_vm_hostname()
        self.vm_username = self.machinecfg.guest_user()
        self.snapshot_id = 0

        # we cannot use the revert mechanism from outside
        assert (False == self.asscfg.revert_to_snapshot('Assignment'))

    def start(self):
        # assume that the vm has been already suspended in a good state
        _logger.info("starting vm %d" % self.vm_id)
        self.revert(self.snapshot_id)
        while not self.hasStarted():
            time.sleep(1)
            _logger.info("start wait for %d" % self.vm_id)

    def stop(self):
        # cleanup the work (do not suspend)
        _logger.info("stopping vm %d" % self.vm_id)
        self.revert(self.snapshot_id)
        while not self.hasStarted():
            time.sleep(1)
            _logger.info("stop wait for %d" % self.vm_id)

    def hasStarted(self):
        state, state_ext = self._get_state()
        if state == 3 and state_ext == 3:
            return True
        return False

    def executeCommand(self, cmd):
        _logger.debug("execute on vm %d: %s" % \
                (self.vm_id, cmd))

        client = self._create_ssh_connection()

        try:
            # this doesn't waits for the commands (I think)
            stdin, stdout, stderr = client.exec_command(cmd)
            stdin.close()
            stdout.close()
            stderr.close()
        finally:
            client.close()

    def revert(self, number=None):
        if not number:
            number = self.snapshot_id
        _logger.info("doing revert to snapshot id %d" % number)

        REVERT_TIMEOUT = 300
        cnt = 0
        while not self.hasStarted() and cnt < REVERT_TIMEOUT:
            cnt += 1
            time.sleep(1)
            _logger.info("revert wait for %d" % self.vm_id)

        if cnt == REVERT_TIMEOUT:
            _logger.warning("probably failing")

        self._rpc('one.vm.snapshotrevert', self.vm_id, number)

    def copyTo(self, sourceDir, targetDir, files):
        _logger.info("copy to vm %d, %s->%s (%s)" % \
                (self.vm_id, sourceDir, targetDir, files))

        t, sftp = self._create_sftp_connection_to_vm()
        try:
            for f in files:
                src_f = os.path.join(sourceDir, f)
                # assume remote path delim == host path delim
                dst_f = os.path.join(targetDir, f)
                sftp.put(src_f, dst_f, confirm=True)
        finally:
            t.close()

    def copyFrom(self, sourceDir, targetDir, files):
        _logger.info("copy from vm %d, %s->%s (%s)" % \
                (self.vm_id, sourceDir, targetDir, files))

        t, sftp = self._create_sftp_connection_to_vm()
        try:
            for f in files:
                src_f = os.path.join(sourceDir, f)
                # assume remote path delim == host path delim
                dst_f = os.path.join(targetDir, f)
                sftp.get(src_f, dst_f)
        finally:
            t.close()

    def run(self, shell, executable_file, timeout):
        _logger.info("run on vm %d: %s %s" % \
                (self.vm_id, shell, executable_file))

        cmd = shell + ' ' + executable_file + ' ' + str(timeout)

        client = self._create_ssh_connection()
        try:
            stdin, stdout, stderr = client.exec_command(cmd)

            while timeout > 0 and not stdout.channel.exit_status_ready():
                time.sleep(1)
                timeout -= 1
                _logger.debug('wait for cmd to finish: [%s]' % cmd)

            stdin.close()
            stdout.close()
            stderr.close()
        finally:
            client.close()

    def _create_ssh_connection(self):
        client = paramiko.SSHClient()
        try:
            # XXX: we should use a more strict policy
            client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            client.connect(self.one_vm_hostname, username=self.vm_username)
        except:
            client.close()
            raise
        return client

    def _create_sftp_connection_to_vm(self):
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        ip = socket.gethostbyname(self.one_vm_hostname)
        sock.connect((ip, 22))
        t = paramiko.Transport(sock)
        try:
            t.start_client()
            sftp = None

            key = paramiko.RSAKey.from_private_key_file(\
                        os.path.join(os.environ['HOME'], '.ssh/id_rsa'))
            t.auth_publickey(self.vm_username, key)
            sftp = paramiko.SFTPClient.from_transport(t)
        except:
            t.close()
            t = None
            sftp = None
            raise

        return (t, sftp)

    def _get_state(self):
        # http://docs.opennebula.org/4.4/integration/system_interfaces/api.html#one-vm-info
        # INIT      = 0
        # PENDING   = 1
        # HOLD      = 2
        # ACTIVE    = 3
        # STOPPED   = 4
        # SUSPENDED = 5
        # DONE      = 6
        # FAILED    = 7
        # POWEROFF  = 8
        # UNDEPLOYED = 9

        #LCM_INIT            = 0,
        #PROLOG              = 1,
        #BOOT                = 2,
        #RUNNING             = 3,
        #MIGRATE             = 4,
        #SAVE_STOP           = 5,
        #SAVE_SUSPEND        = 6,
        #SAVE_MIGRATE        = 7,
        #PROLOG_MIGRATE      = 8,
        #PROLOG_RESUME       = 9,
        #EPILOG_STOP         = 10,
        #EPILOG              = 11,
        #SHUTDOWN            = 12,
        #CANCEL              = 13,
        #FAILURE             = 14,
        #CLEANUP_RESUBMIT    = 15,
        #UNKNOWN             = 16,
        #HOTPLUG             = 17,
        #SHUTDOWN_POWEROFF   = 18,
        #BOOT_UNKNOWN        = 19,
        #BOOT_POWEROFF       = 20,
        #BOOT_SUSPENDED      = 21,
        #BOOT_STOPPED        = 22,
        #CLEANUP_DELETE      = 23,
        #HOTPLUG_SNAPSHOT    = 24,
        #HOTPLUG_NIC         = 25,
        #HOTPLUG_SAVEAS           = 26,
        #HOTPLUG_SAVEAS_POWEROFF  = 27,
        #HOTPLUG_SAVEAS_SUSPENDED = 28,
        #SHUTDOWN_UNDEPLOY   = 29,
        #EPILOG_UNDEPLOY     = 30,
        #PROLOG_UNDEPLOY     = 31,
        #BOOT_UNDEPLOY       = 32

        _, info, _ = self._rpc('one.vm.info', self.vm_id)
        xmldoc = minidom.parseString(info)
        state = int(
            xmldoc.getElementsByTagName('STATE')[0].firstChild.nodeValue)
        state_ext = int(
            xmldoc.getElementsByTagName('LCM_STATE')[0].firstChild.nodeValue)
        if state != 3:
            state_ext = None

        _logger.debug("state form vm %d is (%s:%s)" %
                      (self.vm_id, state, state_ext))
        return (state, state_ext)

    def _get_proxy(self):
        return xmlrpclib.ServerProxy(self.one_server)

    def _rpc(self, *kargs):
        p = self._get_proxy()
        method = getattr(p, kargs[0])
        ret = method(self.one_credentials, *kargs[1:])
        #_logger.debug("%s" % str(ret))
        if not ret[0]:
            raise OneVMException("One RPC: %s" % ret[1])
        return ret