class VMBulkSampler(object): def __init__(self, conn, get_vms, stats_cache, stats_flags=0, ttl=_TTL): self._conn = conn self._get_vms = get_vms self._stats_cache = stats_cache self._stats_flags = stats_flags self._skip_doms = ExpiringCache(ttl) self._sampling = threading.Semaphore() # used as glorified counter self._log = logging.getLogger("virt.sampling.VMBulkSampler") def __call__(self): timestamp = self._stats_cache.clock() acquired = self._sampling.acquire(blocking=False) # we are deep in the hot path. bool(ExpiringCache) # *is* costly so we should avoid it if we can. fast_path = acquired and not self._skip_doms try: if fast_path: # This is expected to be the common case. # If everything's ok, we can skip all the costly checks. bulk_stats = self._conn.getAllDomainStats(self._stats_flags) else: # A previous call got stuck, or not every domain # has properly recovered. Thus we must whitelist domains. doms = self._get_responsive_doms() self._log.debug('sampling %d domains', len(doms)) if doms: bulk_stats = self._conn.domainListGetStats( doms, self._stats_flags) else: bulk_stats = [] except Exception: self._log.exception("vm sampling failed") else: self._stats_cache.put(_translate(bulk_stats), timestamp) finally: if acquired: self._sampling.release() def _get_responsive_doms(self): vms = self._get_vms() doms = [] for vm_id, vm_obj in vms.iteritems(): to_skip = self._skip_doms.get(vm_id, False) if to_skip: continue elif not vm_obj.isDomainReadyForCommands(): self._skip_doms[vm_id] = True else: # TODO: This racy check may fail if the underlying libvirt # domain has died just after checking isDomainReadyForCommands # succeeded. doms.append(vm_obj._dom._dom) return doms
class VMBulkstatsMonitor(object): def __init__(self, conn, get_vms, stats_cache, stats_types=BULK_STATS_TYPES, ttl=_TTL): self._conn = conn self._get_vms = get_vms self._stats_cache = stats_cache self._stats_types = stats_types self._skip_doms = ExpiringCache(ttl) self._sampling = threading.Semaphore() # used as glorified counter self._log = logging.getLogger("virt.sampling.VMBulkstatsMonitor") def __call__(self): log_status = True timestamp = self._stats_cache.clock() acquired = self._sampling.acquire(blocking=False) # we are deep in the hot path. bool(ExpiringCache) # *is* costly so we should avoid it if we can. fast_path = acquired and not self._skip_doms doms = [] # whitelist, meaningful only in the slow path flags = libvirt.VIR_CONNECT_GET_ALL_DOMAINS_STATS_RUNNING if _NOWAIT_ENABLED: flags |= libvirt.VIR_CONNECT_GET_ALL_DOMAINS_STATS_NOWAIT try: if fast_path: # This is expected to be the common case. # If everything's ok, we can skip all the costly checks. bulk_stats = self._conn.getAllDomainStats( stats=self._stats_types, flags=flags) else: # A previous call got stuck, or not every domain # has properly recovered. Thus we must whitelist domains. doms = self._get_responsive_doms() if doms: bulk_stats = self._conn.domainListGetStats( doms, stats=self._stats_types, flags=flags) else: bulk_stats = [] except Exception: self._log.exception("vm sampling failed") log_status = False else: self._stats_cache.put(_translate(bulk_stats), timestamp) finally: if acquired: self._sampling.release() if log_status: self._log.debug( 'sampled timestamp %r elapsed %.3f acquired %r domains %s', timestamp, self._stats_cache.clock() - timestamp, acquired, 'all' if fast_path else len(doms)) def _get_responsive_doms(self): vms = self._get_vms() doms = [] for vm_id, vm_obj in six.iteritems(vms): to_skip = self._skip_doms.get(vm_id, False) if to_skip: continue elif not vm_obj.isDomainReadyForCommands(): self._skip_doms[vm_id] = True else: # TODO: This racy check may fail if the underlying libvirt # domain has died just after checking isDomainReadyForCommands # succeeded. doms.append(vm_obj._dom._dom) return doms
class VMBulkSampler(object): def __init__(self, conn, get_vms, stats_cache, stats_flags=0, ttl=_TTL): self._conn = conn self._get_vms = get_vms self._stats_cache = stats_cache self._stats_flags = stats_flags self._skip_doms = ExpiringCache(ttl) self._sampling = threading.Semaphore() # used as glorified counter self._log = logging.getLogger("virt.sampling.VMBulkSampler") def __call__(self): log_status = True timestamp = self._stats_cache.clock() acquired = self._sampling.acquire(blocking=False) # we are deep in the hot path. bool(ExpiringCache) # *is* costly so we should avoid it if we can. fast_path = acquired and not self._skip_doms doms = [] # whitelist, meaningful only in the slow path try: if fast_path: # This is expected to be the common case. # If everything's ok, we can skip all the costly checks. bulk_stats = self._conn.getAllDomainStats(self._stats_flags) else: # A previous call got stuck, or not every domain # has properly recovered. Thus we must whitelist domains. doms = self._get_responsive_doms() if doms: bulk_stats = self._conn.domainListGetStats( doms, self._stats_flags) else: bulk_stats = [] except Exception: self._log.exception("vm sampling failed") log_status = False else: self._stats_cache.put(_translate(bulk_stats), timestamp) finally: if acquired: self._sampling.release() if log_status: self._log.debug( 'sampled timestamp %r elapsed %.3f acquired %r domains %s', timestamp, self._stats_cache.clock() - timestamp, acquired, 'all' if fast_path else len(doms)) if _METRICS_ENABLED: self._send_metrics() def _send_metrics(self): vms = self._get_vms() vm_samples = self._stats_cache.get_batch() if vm_samples is None: return stats = {} for vm_id, vm_sample in six.iteritems(vm_samples): vm_obj = vms[vm_id] vm_data = vmstats.produce(vm_obj, vm_sample.first_value, vm_sample.last_value, vm_sample.interval) vm_data["vmName"] = vm_obj.name stats[vm_id] = vm_data vmstats.send_metrics(stats) def _get_responsive_doms(self): vms = self._get_vms() doms = [] for vm_id, vm_obj in six.iteritems(vms): to_skip = self._skip_doms.get(vm_id, False) if to_skip: continue elif not vm_obj.isDomainReadyForCommands(): self._skip_doms[vm_id] = True else: # TODO: This racy check may fail if the underlying libvirt # domain has died just after checking isDomainReadyForCommands # succeeded. doms.append(vm_obj._dom._dom) return doms
class VMBulkstatsMonitor(object): def __init__(self, conn, get_vms, stats_cache, stats_types=BULK_STATS_TYPES, ttl=_TTL): self._conn = conn self._get_vms = get_vms self._stats_cache = stats_cache self._stats_types = stats_types self._skip_doms = ExpiringCache(ttl) self._sampling = threading.Semaphore() # used as glorified counter self._log = logging.getLogger("virt.sampling.VMBulkstatsMonitor") def __call__(self): log_status = True timestamp = self._stats_cache.clock() acquired = self._sampling.acquire(blocking=False) # we are deep in the hot path. bool(ExpiringCache) # *is* costly so we should avoid it if we can. fast_path = acquired and not self._skip_doms doms = [] # whitelist, meaningful only in the slow path flags = libvirt.VIR_CONNECT_GET_ALL_DOMAINS_STATS_RUNNING # shortcut try: if fast_path: # This is expected to be the common case. # If everything's ok, we can skip all the costly checks. bulk_stats = self._conn.getAllDomainStats( stats=self._stats_types, flags=flags) else: # A previous call got stuck, or not every domain # has properly recovered. Thus we must whitelist domains. doms = self._get_responsive_doms() if doms: bulk_stats = self._conn.domainListGetStats( doms, stats=self._stats_types, flags=flags) else: bulk_stats = [] except Exception: self._log.exception("vm sampling failed") log_status = False else: self._stats_cache.put(_translate(bulk_stats), timestamp) finally: if acquired: self._sampling.release() if log_status: self._log.debug( 'sampled timestamp %r elapsed %.3f acquired %r domains %s', timestamp, self._stats_cache.clock() - timestamp, acquired, 'all' if fast_path else len(doms)) def _get_responsive_doms(self): vms = self._get_vms() doms = [] for vm_id, vm_obj in six.iteritems(vms): to_skip = self._skip_doms.get(vm_id, False) if to_skip: continue elif not vm_obj.isDomainReadyForCommands(): self._skip_doms[vm_id] = True else: # TODO: This racy check may fail if the underlying libvirt # domain has died just after checking isDomainReadyForCommands # succeeded. doms.append(vm_obj._dom._dom) return doms