Ejemplo n.º 1
0
 def getMapping(self):
     mapping = {}
     for config in self.configManager.configs:
         logger = log.getLogger(config=config)
         virt = Virt.fromConfig(logger, config)
         mapping[config.name or 'none'] = self._readGuests(virt)
     return mapping
Ejemplo n.º 2
0
 def getMapping(self):
     mapping = {}
     for config in self.configManager.configs:
         logger = log.getLogger(self.options, config)
         virt = Virt.fromConfig(logger, config)
         mapping[config.name or 'none'] = self._readGuests(virt)
     return mapping
Ejemplo n.º 3
0
 def run_virt(self, config, in_queue=None):
     v = Virt.fromConfig(self.logger, config)
     v._queue = in_queue or Queue()
     v._terminate_event = Event()
     v._interval = 3600
     v._oneshot = True
     v._run()
Ejemplo n.º 4
0
class VirtTest(unittest.TestCase):
    def setUp(self):
        self.virt = Virt(logger)

    def test_connection(self):
        self.assertTrue(self.virt.virt.getVersion() > 0)

    def test_listDomains(self):
        uuids = []
        for domain in self.virt.listDomains():
            uuids.append(domain.UUIDString())
        virsh_list = subprocess.Popen(["virsh", "-r", "list", "--all"],
                                      stdout=subprocess.PIPE).communicate()[0]
        lines = virsh_list.split("\n")[2:]
        for line in lines:
            if len(line) == 0:
                continue
            domId = line.split()[1]
            uuid = subprocess.Popen(
                ["virsh", "-r", "domuuid", domId],
                stdout=subprocess.PIPE).communicate()[0].strip()
            self.assertTrue(
                uuid in uuids,
                "virsh returns more domains then virt-who (%s)" % uuid)
            uuids.remove(uuid)
        self.assertEqual(
            len(uuids), 0,
            "virsh returns less domains then virt-who (%s)" % ",".join(uuids))
Ejemplo n.º 5
0
    def test_read_hypervisor(self):
        with open(self.hypervisor_file, "w") as f:
            f.write(HYPERVISOR_JSON)

        with open(self.config_file, "w") as f:
            f.write("""
[test]
type=fake
is_hypervisor=true
file=%s
""" % self.hypervisor_file)

        manager = ConfigManager(self.logger, self.config_dir)
        self.assertEquals(len(manager.configs), 1)
        virt = Virt.fromConfig(self.logger, manager.configs[0])
        self.assertEquals(type(virt), FakeVirt)
        mapping = virt.getHostGuestMapping()
        self.assertTrue("hypervisors" in mapping)
        hypervisors = mapping["hypervisors"]
        self.assertEquals(len(hypervisors), 1)
        hypervisor = hypervisors[0]
        self.assertEquals(type(hypervisor), Hypervisor)
        self.assertEquals(hypervisor.hypervisorId,
                          "60527517-6284-7593-6AAB-75BF2A6375EF")
        self.assertEquals(len(hypervisor.guestIds), 1)
        guest = hypervisor.guestIds[0]
        self.assertEquals(guest.uuid, "07ED8178-95D5-4244-BC7D-582A54A48FF8")
        self.assertEquals(guest.state, 1)
Ejemplo n.º 6
0
    def test_read_hypervisor(self):
        with open(self.hypervisor_file, "w") as f:
            f.write(HYPERVISOR_JSON)

        with open(self.config_file, "w") as f:
            f.write("""
[test]
type=fake
is_hypervisor=true
file=%s
""" % self.hypervisor_file)

        manager = ConfigManager(self.logger, self.config_dir)
        self.assertEquals(len(manager.configs), 1)
        virt = Virt.fromConfig(self.logger, manager.configs[0])
        self.assertEquals(type(virt), FakeVirt)
        mapping = virt.getHostGuestMapping()
        self.assertTrue("hypervisors" in mapping)
        hypervisors = mapping["hypervisors"]
        self.assertEquals(len(hypervisors), 1)
        hypervisor = hypervisors[0]
        self.assertEquals(type(hypervisor), Hypervisor)
        self.assertEquals(hypervisor.hypervisorId, "60527517-6284-7593-6AAB-75BF2A6375EF")
        self.assertEquals(len(hypervisor.guestIds), 1)
        guest = hypervisor.guestIds[0]
        self.assertEquals(guest.uuid, "07ED8178-95D5-4244-BC7D-582A54A48FF8")
        self.assertEquals(guest.state, 1)
Ejemplo n.º 7
0
 def _readGuests(self, config):
     virt = Virt.fromConfig(self.logger, config)
     if not self.options.oneshot and virt.canMonitor():
         virt.startMonitoring(self.sync_event)
     if config.type not in ["esx", "rhevm", "hyperv"]:
         return virt.listDomains()
     else:
         return virt.getHostGuestMapping()
Ejemplo n.º 8
0
    def test_read_non_hypervisor_from_hypervisor(self):
        with open(self.hypervisor_file, "w") as f:
            f.write(HYPERVISOR_JSON)

        with open(self.config_file, "w") as f:
            f.write("""
[test]
type=fake
is_hypervisor=false
file=%s
""" % self.hypervisor_file)

        manager = ConfigManager(self.logger, self.config_dir)
        self.assertEquals(len(manager.configs), 1)
        virt = Virt.fromConfig(self.logger, manager.configs[0])
        self.assertEquals(type(virt), FakeVirt)
        self.assertRaises(VirtError, virt.listDomains)
Ejemplo n.º 9
0
    def test_read_non_hypervisor_from_hypervisor(self):
        with open(self.hypervisor_file, "w") as f:
            f.write(HYPERVISOR_JSON)

        with open(self.config_file, "w") as f:
            f.write("""
[test]
type=fake
is_hypervisor=false
file=%s
""" % self.hypervisor_file)

        manager = ConfigManager(self.logger, self.config_dir)
        self.assertEquals(len(manager.configs), 1)
        virt = Virt.fromConfig(self.logger, manager.configs[0])
        self.assertEquals(type(virt), FakeVirt)
        self.assertRaises(VirtError, virt.listDomains)
Ejemplo n.º 10
0
 def initVirt(self):
     """
     Connect to the virtualization supervisor (libvirt or VDSM)
     """
     if self.options.virtType == "vdsm":
         self.virt = VDSM(self.logger)
     elif self.options.virtType == "libvirt":
         self.virt = Virt(self.logger, registerEvents=self.options.background)
         # We can listen for libvirt events
         self.tryRegisterEventCallback()
     elif self.options.virtType == "rhevm":
         self.virt = RHEVM(self.logger, self.options.server, self.options.username, self.options.password)
     elif self.options.virtType == "hyperv":
         self.virt = HyperV(self.logger, self.options.server, self.options.username, self.options.password)
     else:
         # ESX
         self.virt = VSphere(self.logger, self.options.server, self.options.username, self.options.password)
Ejemplo n.º 11
0
class VirtTest(unittest.TestCase):
    def setUp(self):
        self.virt = Virt(logger)

    def test_connection(self):
        self.assertTrue(self.virt.virt.getVersion() > 0)

    def test_listDomains(self):
        uuids = []
        for domain in self.virt.listDomains():
            uuids.append(domain.UUIDString())
        virsh_list = subprocess.Popen(["virsh", "-r", "list", "--all"], stdout=subprocess.PIPE).communicate()[0]
        lines = virsh_list.split("\n")[2:]
        for line in lines:
            if len(line) == 0:
                continue
            domId = line.split()[1]
            uuid = subprocess.Popen(["virsh", "-r", "domuuid", domId], stdout=subprocess.PIPE).communicate()[0].strip()
            self.assertTrue(uuid in uuids, "virsh returns more domains then virt-who (%s)" % uuid)
            uuids.remove(uuid)
        self.assertEqual(len(uuids), 0, "virsh returns less domains then virt-who (%s)" % ",".join(uuids))
Ejemplo n.º 12
0
    def test_read_non_hypervisor(self):
        with open(self.hypervisor_file, "w") as f:
            f.write(NON_HYPERVISOR_JSON)

        with open(self.config_file, "w") as f:
            f.write("""
[test]
type=fake
is_hypervisor=false
file=%s
""" % self.hypervisor_file)

        manager = ConfigManager(self.logger, self.config_dir)
        self.assertEquals(len(manager.configs), 1)
        virt = Virt.fromConfig(self.logger, manager.configs[0])
        self.assertEquals(type(virt), FakeVirt)
        guests = virt.listDomains()
        self.assertEquals(len(guests), 1)
        guest = guests[0]
        self.assertEquals(guest.uuid, "9f06a84d-5f56-4e7e-be0c-937b3c1924d7")
        self.assertEquals(guest.state, 1)
Ejemplo n.º 13
0
    def test_read_non_hypervisor(self):
        with open(self.hypervisor_file, "w") as f:
            f.write(NON_HYPERVISOR_JSON)

        with open(self.config_file, "w") as f:
            f.write("""
[test]
type=fake
is_hypervisor=false
file=%s
""" % self.hypervisor_file)

        manager = ConfigManager(self.logger, self.config_dir)
        self.assertEquals(len(manager.configs), 1)
        virt = Virt.fromConfig(self.logger, manager.configs[0])
        self.assertEquals(type(virt), FakeVirt)
        guests = virt.listDomains()
        self.assertEquals(len(guests), 1)
        guest = guests[0]
        self.assertEquals(guest.uuid, "9f06a84d-5f56-4e7e-be0c-937b3c1924d7")
        self.assertEquals(guest.state, 1)
Ejemplo n.º 14
0
    def _send(self, config, retry):
        """
        Send list of uuids to subscription manager. This method will call itself
        once if sending fails.

        retry - Should be True on first run, False on second.
        return - True if sending is successful, False otherwise
        """
        virt = Virt.fromConfig(self.logger, config)
        try:
            virtualGuests = self._readGuests(virt)
        except (KeyboardInterrupt, SystemExit):
            raise
        except Exception, e:
            exceptionCheck(e)
            # Retry once
            if retry:
                self.logger.exception("Error in communication with virtualization backend, trying to recover:")
                return self._send(config, False)
            else:
                self.logger.error(self.unableToRecoverStr)
                return False
Ejemplo n.º 15
0
    def run(self):
        self.reloading = False
        if not self.options.oneshot:
            self.logger.debug("Starting infinite loop with %d seconds interval" % self.options.interval)

        # Queue for getting events from virt backends
        if self.queue is None:
            self.queue = Queue(len(self.configManager.configs))

        # Run the virtualization backends
        self.virts = []
        for config in self.configManager.configs:
            try:
                virt = Virt.fromConfig(self.logger, config)
            except Exception as e:
                self.logger.error('Unable to use configuration "%s": %s' % (config.name, str(e)))
                continue
            # Run the process
            virt.start(self.queue, self.terminate_event, self.options.interval, self.options.oneshot)
            self.virts.append(virt)
        if self.options.oneshot:
            oneshot_remaining = set(virt.config.name for virt in self.virts)

        if len(self.virts) == 0:
            self.logger.error("No suitable virt backend found")
            return

        result = {}
        report = None
        while not self.terminate_event.is_set():
            # Wait for incoming report from virt backend
            try:
                report = self.queue.get(block=True, timeout=None)
            except Empty:
                report = None
                pass
            except IOError:
                continue

            try:
                # Run all jobs that have been queued as a result of sending last
                # time
                self.runJobs()
            except Empty:
                pass
            except IOError:
                pass

            # FIXME Not sure about how to integrate this into the new jobs
            # scheme of things
            if report is not None:
                if report == "exit":
                    break
                if report == "reload":
                    for virt in self.virts:
                        virt.terminate()
                    self.virts = []
                    raise ReloadRequest()

                # Send the report
                if not self.options.print_ and not isinstance(report, ErrorReport):
                    try:
                        self.send(report)
                    except ManagerFatalError:
                        # System not register (probably), stop the backends
                        for virt in self.virts:
                            virt.terminate()
                        self.virts = []

                if self.options.oneshot:
                    try:
                        oneshot_remaining.remove(report.config.name)
                        if not isinstance(report, ErrorReport):
                            if self.options.print_:
                                result[report.config] = report
                            self.logger.debug("Association for config %s gathered" % report.config.name)
                        for virt in self.virts:
                            if virt.config.name == report.config.name:
                                virt.stop()
                    except KeyError:
                        self.logger.debug("Association for config %s already gathered, ignoring" % report.config.name)
                    if not oneshot_remaining:
                        break

        self.queue = None
        self.jobs = None
        for virt in self.virts:
            virt.terminate()

        self.virt = []
        if self.options.print_:
            return result
Ejemplo n.º 16
0
 def test_read_fail(self, virt):
     logger = logging.getLogger()
     config = Config('test', 'libvirt')
     libvirtd = Virt.fromConfig(logger, config)
     virt.side_effect = raiseLibvirtError
     self.assertRaises(VirtError, libvirtd.listDomains)
Ejemplo n.º 17
0
 def test_read(self, libvirt):
     logger = logging.getLogger()
     config = Config('test', 'libvirt')
     libvirtd = Virt.fromConfig(logger, config)
     domains = libvirtd.listDomains()
     libvirt.assert_called_with("")
Ejemplo n.º 18
0
 def setUp(self):
     self.virt = Virt(logger)
Ejemplo n.º 19
0
 def test_read(self, libvirt):
     config = Config('test', 'libvirt')
     libvirtd = Virt.fromConfig(self.logger, config)
     self.run_virt(config)
     libvirt.assert_called_with("")
Ejemplo n.º 20
0
 def test_remote_url_with_username_and_password(self, virt):
     config = Config('test', 'libvirt', 'abc://server/test', 'user', 'pass')
     Virt.fromConfig(self.logger, config).listDomains()
     virt.assert_called_with('abc://user@server/test?no_tty=1', ANY, ANY)
Ejemplo n.º 21
0
 def test_read(self, libvirt):
     config = Config('test', 'libvirt')
     libvirtd = Virt.fromConfig(self.logger, config)
     domains = libvirtd.listDomains()
     libvirt.assert_called_with("")
Ejemplo n.º 22
0
 def test_read_fail(self, virt):
     config = Config('test', 'libvirt')
     libvirtd = Virt.fromConfig(self.logger, config)
     virt.side_effect = raiseLibvirtError
     self.assertRaises(VirtError, libvirtd.listDomains)
Ejemplo n.º 23
0
    def run(self):
        self.reloading = False
        if not self.options.oneshot:
            self.logger.debug("Starting infinite loop with %d seconds interval" % self.options.interval)

        # Queue for getting events from virt backends
        if self.queue is None:
            self.queue = Queue()

        # Run the virtualization backends
        self.virts = []
        for config in self.configManager.configs:
            try:
                logger = log.getLogger(config=config)
                virt = Virt.fromConfig(logger, config)
            except Exception as e:
                self.logger.error('Unable to use configuration "%s": %s' % (config.name, str(e)))
                continue
            # Run the process
            virt.start(self.queue, self.terminate_event, self.options.interval, self.options.oneshot)
            self.virts.append(virt)
        if self.options.oneshot or self.options.print_:
            oneshot_remaining = set(virt.config.name for virt in self.virts)

        if len(self.virts) == 0:
            self.logger.error("No suitable virt backend found")
            return

        result = {}
        report = None
        report_sent = None
        while not self.terminate_event.is_set():
            if self.jobs:
                # There is an existing job, we want to check it's state often
                timeout = 1
            else:
                timeout = self.queue_timeout

            # Wait for incoming report from virt backend
            try:
                report = self.queue.get(block=True, timeout=timeout)
            except Empty:
                report = None
            except IOError:
                continue

            # Read all the reports from the queue in order to remove obsoleted
            # reports from same virt
            reports = [report]
            while True:
                try:
                    report = self.queue.get(block=False)
                    reports.append(report)
                except Empty:
                    break
            reports = self._remove_obsolete(reports)

            try:
                # Run all jobs that have been queued as a result of sending last
                # time
                self.runJobs()
                if self.options.oneshot and not oneshot_remaining and not self.jobs:
                    break
            except Empty:
                pass
            except IOError:
                pass

            report_sent = None
            for report in reports:
                if report == "exit":
                    break
                if report == "reload":
                    self.stop_virts()
                    raise ReloadRequest()
                if isinstance(report, ErrorReport):
                    if self.options.oneshot:
                        # Don't hang on the failed backend
                        oneshot_remaining.remove(report.config.name)
                        self.logger.warn('Unable to collect report for config "%s"' % report.config.name)
                # Send the report
                if not self.options.print_ and not isinstance(report, ErrorReport):
                    self.update_report_to_send(report)
            # Check to see if it is time to send a report
            try:
                if time.time() >= self.send_after:
                    # It is time, send the current report
                    config, report_sent = self.send_current_report()
                else:
                    # It's not time update our queue_timeout to make sure we
                    # don't wait too long
                    wait_time = self.send_after - time.time()
                    self.queue_timeout = max(0, wait_time)
                    self.logger.debug('Waiting to send report')
            except ManagerFatalError:
                # System not register (probably), stop the backends
                self.stop_virts()
                continue

            if self.options.print_:
                report_sent = report

            if (self.options.oneshot and report_sent) or self.options.print_:
                try:
                    oneshot_remaining.remove(report_sent.config.name)
                except KeyError:
                    pass
                if not isinstance(report_sent, ErrorReport):
                    if self.options.print_:
                        result[report_sent.config] = report_sent
                for virt in self.virts:
                    if virt.config.name == report_sent.config.name:
                        virt.stop()
                if not oneshot_remaining and not self.jobs:
                    break
        self.queue = None
        self.jobs = None
        self.stop_virts()

        self.virt = []
        if self.options.print_:
            return result
Ejemplo n.º 24
0
 def test_remote_url(self, virt):
     config = Config('test', 'libvirt', 'abc://server/test')
     Virt.fromConfig(self.logger, config).listDomains()
     virt.assert_called_with('abc://server/test?no_tty=1')
Ejemplo n.º 25
0
    def run(self):
        self.queue_logger = log.getDefaultQueueLogger()

        self.reloading = False
        if not self.options.oneshot:
            self.logger.debug(
                "Starting infinite loop with %d seconds interval" %
                self.options.interval)

        # Queue for getting events from virt backends
        if self.queue is None:
            self.queue = Queue()

        # Run the virtualization backends
        self.virts = []
        for config in self.configManager.configs:
            try:
                logger = log.getLogger(self.options, config)
                virt = Virt.fromConfig(logger, config)
            except Exception as e:
                self.logger.error('Unable to use configuration "%s": %s' %
                                  (config.name, str(e)))
                continue
            # Run the process
            virt.start(self.queue, self.terminate_event, self.options.interval,
                       self.options.oneshot)
            self.virts.append(virt)
        if self.options.oneshot:
            oneshot_remaining = set(virt.config.name for virt in self.virts)

        if len(self.virts) == 0:
            self.logger.error("No suitable virt backend found")
            return

        result = {}
        report = None
        report_sent = None
        while not self.terminate_event.is_set():
            # Wait for incoming report from virt backend
            try:
                report = self.queue.get(block=True, timeout=self.queue_timeout)
            except Empty:
                report = None
            except IOError:
                continue

            # Read all the reports from the queue in order to remove obsoleted
            # reports from same virt
            reports = [report]
            while True:
                try:
                    report = self.queue.get(block=False)
                    reports.append(report)
                except Empty:
                    break
            reports = self._remove_obsolete(reports)

            try:
                # Run all jobs that have been queued as a result of sending last
                # time
                self.runJobs()
                if self.options.oneshot and not oneshot_remaining and not self.jobs:
                    break
            except Empty:
                pass
            except IOError:
                pass

            report_sent = None
            for report in reports:
                if report == "exit":
                    break
                if report == "reload":
                    self.stop_virts()
                    raise ReloadRequest()
                if isinstance(report, ErrorReport):
                    if self.options.oneshot:
                        # Don't hang on the failed backend
                        oneshot_remaining.remove(report.config.name)
                        self.logger.warn(
                            'Unable to collect report for config "%s"' %
                            report.config.name)
                # Send the report
                if not self.options.print_ and not isinstance(
                        report, ErrorReport):
                    self.update_report_to_send(report)
            # Check to see if it is time to send a report
            try:
                if time.time() >= self.send_after:
                    # It is time, send the current report
                    config, report_sent = self.send_current_report()
                else:
                    # It's not time update our queue_timeout to make sure we
                    # don't wait too long
                    wait_time = self.send_after - time.time()
                    self.queue_timeout = max(0, wait_time)
                    self.logger.debug('Waiting to send report')
            except ManagerFatalError:
                # System not register (probably), stop the backends
                self.stop_virts()
                continue

            if self.options.print_:
                report_sent = report

            if (self.options.oneshot and report_sent) or self.options.print_:
                oneshot_remaining.remove(report_sent.config.name)
                if not isinstance(report_sent, ErrorReport):
                    if self.options.print_:
                        result[report_sent.config] = report_sent
                for virt in self.virts:
                    if virt.config.name == report_sent.config.name:
                        virt.stop()
                if not oneshot_remaining and not self.jobs:
                    break
        self.queue = None
        self.jobs = None
        self.stop_virts()

        self.virt = []
        if self.options.print_:
            return result
Ejemplo n.º 26
0
 def test_remote_hostname_with_username(self, virt):
     config = Config('test', 'libvirt', 'server', 'user')
     Virt.fromConfig(self.logger, config).listDomains()
     virt.assert_called_with('qemu+ssh://user@server/system?no_tty=1')
Ejemplo n.º 27
0
 def setUp(self):
     self.virt = Virt(logger)
Ejemplo n.º 28
0
 def getMapping(self):
     mapping = {}
     for config in self.configManager.configs:
         virt = Virt.fromConfig(self.logger, config)
         mapping[config.name or "none"] = self._readGuests(virt)
     return mapping
Ejemplo n.º 29
0
    def run(self):
        self.reloading = False
        if not self.options.oneshot:
            self.logger.debug("Starting infinite loop with %d seconds interval", self.options.interval)

        # Queue for getting events from virt backends
        if self.queue is None:
            self.queue = Queue()

        # Run the virtualization backends
        self.virts = []
        for config in self.configManager.configs:
            try:
                logger = log.getLogger(config=config)
                virt = Virt.fromConfig(logger, config)
            except Exception as e:
                self.logger.error('Unable to use configuration "%s": %s', config.name, str(e))
                continue
            # Run the process
            virt.start(self.queue, self.terminate_event, self.options.interval, self.options.oneshot)
            self.virts.append(virt)
        if self.options.oneshot:
            self.oneshot_remaining = set(virt.config.name for virt in self.virts)

        if len(self.virts) == 0:
            self.logger.error("No suitable virt backend found")
            return

        # queued reports depend on OrderedDict feature that if key exists
        # when setting an item, it will remain in the same order
        self.queued_reports.clear()

        # Clear last reports, we need to resend them when reloaded
        self.last_reports_hash.clear()

        # List of reports that are being processed by server
        self.reports_in_progress = []

        # Send the first report immediatelly
        self.send_after = time.time()

        while not self.terminate_event.is_set():
            if self.reports_in_progress:
                # Check sent report status regularly
                timeout = 1
            elif time.time() > self.send_after:
                if self.queued_reports:
                    # Reports are queued and we can send them right now,
                    # don't wait in queue
                    timeout = 0
                else:
                    # No reports in progress or queued and we can send report
                    # immediately, we can wait for report as long as we want
                    timeout = 3600
            else:
                # We can't send report right now, wait till we can
                timeout = max(1, self.send_after - time.time())

            # Wait for incoming report from virt backend or for timeout
            try:
                report = self.queue.get(block=True, timeout=timeout)
            except Empty:
                report = None
            except IOError:
                continue

            # Read rest of the reports from the queue in order to remove
            # obsoleted reports from same virt
            while True:
                if isinstance(report, ErrorReport):
                    if self.options.oneshot:
                        # Don't hang on the failed backend
                        try:
                            self.oneshot_remaining.remove(report.config.name)
                        except KeyError:
                            pass
                        self.logger.warn('Unable to collect report for config "%s"', report.config.name)
                elif isinstance(report, AbstractVirtReport):
                    if self.last_reports_hash.get(report.config.name, None) == report.hash:
                        self.logger.info('Report for config "%s" haven\'t changed, not sending', report.config.name)
                    else:
                        self.queued_reports[report.config.name] = report
                        if self.options.print_:
                            try:
                                self.oneshot_remaining.remove(report.config.name)
                            except KeyError:
                                pass
                elif report in ['exit', 'reload']:
                    # Reload and exit reports takes priority, do not process
                    # any other reports
                    break
                try:
                    report = self.queue.get(block=False)
                except Empty:
                    break

            if report == 'exit':
                break
            elif report == 'reload':
                self.stop_virts()
                raise ReloadRequest()

            self.check_reports_state()

            if not self.reports_in_progress and self.queued_reports and time.time() > self.send_after:
                # No report is processed, send next one
                if not self.options.print_:
                    self.send_current_report()

            if self.options.oneshot and not self.oneshot_remaining:
                break

        self.queue = None
        self.stop_virts()

        self.virt = []
        if self.options.print_:
            return self.queued_reports