Пример #1
0
    def inspect_vnics(self, instance, duration):
        """Inspect the vNIC statistics for an instance.

        :param instance: the target instance
        :param duration: the last 'n' seconds, over which the value should be
               inspected.

               The PowerVM implementation does not make use of the duration
               field.
        :return: for each vNIC, the number of bytes & packets
                 received and transmitted
        """
        # Get the current and previous sample.  Delta is performed between
        # these two.
        uuid = self._puuid(instance)
        cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid)

        # If the cur_metric is none, then the instance can not be found in the
        # sample and an error should be raised.
        if cur_metric is None:
            raise virt_inspector.InstanceNotFoundException(
                _('VM %s not found in PowerVM Metrics Sample.') %
                instance.name)

        # If there isn't network information, this is because the Virtual
        # I/O Metrics were turned off.  Have to pass through this method.
        if cur_metric.network is None:
            return

        # Get the network interfaces.  A 'cna' is a Client VM's Network Adapter
        client_cnas = self._get_cnas(uuid)

        for metric_cna in cur_metric.network.cnas:
            # Get the mac, but if it isn't found, then move to the next.  Might
            # have been removed since the last sample.
            mac = self.mac_for_metric_cna(metric_cna, client_cnas)
            if mac is None:
                continue

            # The name will be the location code.  MAC is identified from
            # above.  Others appear libvirt specific.
            #
            # PowerVM doesn't specify drops by receive vs. transmit.  Since we
            # have the client adapter, we assume all are receive drops.
            # There are no error metrics available.
            yield virt_inspector.InterfaceStats(
                name=metric_cna.physical_location,
                mac=mac,
                fref=None,
                parameters=None,
                rx_bytes=metric_cna.received_bytes,
                rx_packets=metric_cna.received_packets,
                rx_drop=metric_cna.dropped_packets,
                rx_errors=0,
                tx_bytes=metric_cna.sent_bytes,
                tx_packets=metric_cna.sent_packets,
                tx_drop=0,
                tx_errors=0)
Пример #2
0
    def inspect_vnics(self, instance):
        """Inspect the vNIC statistics for an instance.

        :param instance: the target instance
        :return: for each vNIC, the number of bytes & packets
                 received and transmitted
        """
        # Get the current and previous sample.  Delta is performed between
        # these two.
        uuid = self._puuid(instance)
        cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid)

        # If the cur_metric is none, then the instance can not be found in the
        # sample and an error should be raised.
        if cur_metric is None:
            raise virt_inspector.InstanceNotFoundException(
                _('VM %s not found in PowerVM Metrics Sample.') %
                instance.name)

        # If there isn't network information, this is because the Virtual
        # I/O Metrics were turned off.  Have to pass through this method.
        if cur_metric.network is None:
            return

        # Get the network interfaces.  A 'cna' is a Client VM's Network Adapter
        client_cnas = self._get_cnas(uuid)

        for metric_cna in cur_metric.network.cnas:
            # Get the mac, but if it isn't found, then move to the next.  Might
            # have been removed since the last sample.
            mac = self.mac_for_metric_cna(metric_cna, client_cnas)
            if mac is None:
                continue

            # The name will be the location code.  MAC is identified from
            # above.  Others appear libvirt specific.
            interface = virt_inspector.Interface(
                name=metric_cna.physical_location,
                mac=mac,
                fref=None,
                parameters=None)

            stats = virt_inspector.InterfaceStats(
                rx_bytes=metric_cna.received_bytes,
                rx_packets=metric_cna.received_packets,
                tx_bytes=metric_cna.sent_bytes,
                tx_packets=metric_cna.sent_packets)

            # Yield the stats up to the invoker
            yield (interface, stats)
Пример #3
0
    def inspect_disks(self, instance, duration):
        """Inspect the disk statistics for an instance.

        The response is a generator of the values.

        :param instance: the target instance
        :param duration: the last 'n' seconds, over which the value should be
               inspected.

               The PowerVM implementation does not make use of the duration
               field.
        :return disk: The Disk indicating the device for the storage device.
        :return stats: The DiskStats indicating the read/write data to the
                       device.
        """
        # Get the current and previous sample.  Delta is performed between
        # these two.
        uuid = self._puuid(instance)
        cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid)

        # If the cur_metric is none, then the instance can not be found in the
        # sample and an error should be raised.
        if cur_metric is None:
            raise virt_inspector.InstanceNotFoundException(
                _('VM %s not found in PowerVM Metrics Sample.') %
                instance.name)

        # If there isn't storage information, this is because the Virtual
        # I/O Metrics were turned off.  Have to pass through this method.
        if cur_metric.storage is None:
            LOG.debug("Current storage metric was unavailable from the API "
                      "instance %s." % instance.name)
            return

        # Bundle together the SCSI and virtual FC adapters
        adpts = cur_metric.storage.virt_adpts + cur_metric.storage.vfc_adpts

        # Loop through all the storage adapters
        for adpt in adpts:
            # PowerVM only shows the connection (SCSI or FC).  Name after
            # the connection name
            yield virt_inspector.DiskStats(device=adpt.name,
                                           read_requests=adpt.num_reads,
                                           read_bytes=adpt.read_bytes,
                                           write_requests=adpt.num_writes,
                                           write_bytes=adpt.write_bytes,
                                           errors=0,
                                           wr_total_times=0,
                                           rd_total_times=0)
Пример #4
0
    def _get_host_uuid(self, adpt):
        """Returns the Host system's UUID for pypowervm.

        The pypowervm API needs a UUID of the server that it is managing.  This
        method returns the UUID of that host.

        :param adpt: The pypowervm adapter.
        :return: The UUID of the host system.
        """
        hosts = pvm_ms.System.wrap(adpt.read(pvm_ms.System.schema_type))
        if len(hosts) != 1:
            raise Exception(_("Expected exactly one host; found %d."),
                            len(hosts))
        LOG.debug("Host UUID: %s" % hosts[0].uuid)
        return hosts[0].uuid
Пример #5
0
    def _get_host_uuid(self, adpt):
        """Returns the Host systems UUID for pypowervm.

        The pypowervm API needs a UUID of the server that it is managing.  This
        method returns the UUID of that host.

        :param adpt: The pypowervm adapter.
        :return: The UUID of the host system.
        """
        hosts = pvm_ms.System.wrap(adpt.read(pvm_ms.System.schema_type))
        if len(hosts) != 1:
            raise Exception(_("Expected exactly one host; found %d."),
                            len(hosts))
        LOG.debug("Host UUID: %s" % hosts[0].uuid)
        return hosts[0].uuid
Пример #6
0
    def inspect_vnics(self, instance):
        """Inspect the vNIC statistics for an instance.

        :param instance: the target instance
        :return: for each vNIC, the number of bytes & packets
                 received and transmitted
        """
        # Get the current and previous sample.  Delta is performed between
        # these two.
        uuid = self._puuid(instance)
        cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid)

        # If the cur_metric is none, then the instance can not be found in the
        # sample and an error should be raised.
        if cur_metric is None:
            raise virt_inspector.InstanceNotFoundException(
                _('VM %s not found in PowerVM Metrics Sample.') %
                instance.name)

        # If there isn't network information, this is because the Virtual
        # I/O Metrics were turned off.  Have to pass through this method.
        if cur_metric.network is None:
            return

        # Get the network interfaces.  A 'cna' is a Client VM's Network Adapter
        client_cnas = self._get_cnas(uuid)

        for metric_cna in cur_metric.network.cnas:
            # Get the mac, but if it isn't found, then move to the next.  Might
            # have been removed since the last sample.
            mac = self.mac_for_metric_cna(metric_cna, client_cnas)
            if mac is None:
                continue

            # The name will be the location code.  MAC is identified from
            # above.  Others appear libvirt specific.
            interface = virt_inspector.Interface(
                name=metric_cna.physical_location,
                mac=mac, fref=None, parameters=None)

            stats = virt_inspector.InterfaceStats(
                rx_bytes=metric_cna.received_bytes,
                rx_packets=metric_cna.received_packets,
                tx_bytes=metric_cna.sent_bytes,
                tx_packets=metric_cna.sent_packets)

            # Yield the stats up to the invoker
            yield (interface, stats)
Пример #7
0
    def inspect_disks(self, instance):
        """Inspect the disk statistics for an instance.

        The response is a generator of the values.

        :param instance: the target instance
        :return disk: The Disk indicating the device for the storage device.
        :return stats: The DiskStats indicating the read/write data to the
                       device.
        """
        # Get the current and previous sample.  Delta is performed between
        # these two.
        uuid = self._puuid(instance)
        cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid)

        # If the cur_metric is none, then the instance can not be found in the
        # sample and an error should be raised.
        if cur_metric is None:
            raise virt_inspector.InstanceNotFoundException(
                _('VM %s not found in PowerVM Metrics Sample.') %
                instance.name)

        # If there isn't storage information, this is because the Virtual
        # I/O Metrics were turned off.  Have to pass through this method.
        if cur_metric.storage is None:
            LOG.debug("Current storage metric was unavailable from the API "
                      "instance %s." % instance.name)
            return

        # Bundle together the SCSI and virtual FC adapters
        adpts = cur_metric.storage.virt_adpts + cur_metric.storage.vfc_adpts

        # Loop through all the storage adapters
        for adpt in adpts:
            # PowerVM only shows the connection (SCSI or FC).  Name after
            # the connection name
            disk = virt_inspector.Disk(device=adpt.name)
            stats = virt_inspector.DiskStats(
                read_requests=adpt.num_reads, read_bytes=adpt.read_bytes,
                write_requests=adpt.num_writes, write_bytes=adpt.write_bytes,
                errors=0)
            yield (disk, stats)
Пример #8
0
    def inspect_cpus(self, instance):
        """Inspect the CPU statistics for an instance.

        :param instance: the target instance
        :return: the number of CPUs and cumulative CPU time
        """
        uuid = self._puuid(instance)
        cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid)

        # If the current metric is none, then the instance can not be found in
        # the sample set.  An error should be raised.
        if cur_metric is None:
            raise virt_inspector.InstanceNotFoundException(
                _('VM %s not found in PowerVM Metrics Sample.') %
                instance.name)

        cpu_time = (cur_metric.processor.util_cap_proc_cycles +
                    cur_metric.processor.util_uncap_proc_cycles)
        return virt_inspector.CPUStats(number=cur_metric.processor.virt_procs,
                                       time=cpu_time)
Пример #9
0
    def inspect_cpus(self, instance):
        """Inspect the CPU statistics for an instance.

        :param instance: the target instance
        :return: the number of CPUs and cumulative CPU time
        """
        uuid = self._puuid(instance)
        cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid)

        # If the current metric is none, then the instance can not be found in
        # the sample set.  An error should be raised.
        if cur_metric is None:
            raise virt_inspector.InstanceNotFoundException(
                _('VM %s not found in PowerVM Metrics Sample.') %
                instance.name)

        cpu_time = (cur_metric.processor.util_cap_proc_cycles +
                    cur_metric.processor.util_uncap_proc_cycles)
        return virt_inspector.CPUStats(number=cur_metric.processor.virt_procs,
                                       time=cpu_time)
Пример #10
0
    def inspect_instance(self, instance, duration):
        """Inspect the statistics for an instance.

        :param instance: the target instance
        :param duration: the last 'n' seconds, over which the value should be
               inspected.

               The PowerVM implementation does not make use of the duration
               field.
        :return: the instance statistics
        """

        uuid = self._puuid(instance)
        cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid)

        # If the current metric is none, then the instance can not be found in
        # the sample set.  An error should be raised.
        if cur_metric is None:
            raise virt_inspector.InstanceNotFoundException(
                _('VM %s not found in PowerVM Metrics Sample.') %
                instance.name)

        cpu_time = (cur_metric.processor.util_cap_proc_cycles +
                    cur_metric.processor.util_uncap_proc_cycles)
        cpu_num = cur_metric.processor.virt_procs

        # The duration is ignored.  There is precedent for this in other
        # inspectors if the platform doesn't support duration.
        #
        # Given the nature of PowerVM to collect samples over coarse periods
        # of time, it does not lend well to duration based collection.
        # Therefore this works by gathering the latest utilization from the
        # samples and ignores the duration.

        # Get the current and previous sample.  Delta is performed between
        # these two.
        prev_date, prev_metric = self.vm_metrics.get_previous_metric(uuid)

        # Get the current data.
        cur_util_cap = cur_metric.processor.util_cap_proc_cycles
        cur_util_uncap = cur_metric.processor.util_uncap_proc_cycles
        cur_idle = cur_metric.processor.idle_proc_cycles
        cur_donated = cur_metric.processor.donated_proc_cycles
        cur_entitled = cur_metric.processor.entitled_proc_cycles

        # Get the previous sample data
        if prev_metric is None:
            # If there is no previous sample, that is either a new VM or is
            # a live migrated system.  A live migrated system will pull all
            # of its metrics with it.  The issue with this is it could have
            # CPU cycles for months of run time.  So we can't really determine
            # the CPU utilization within the last X seconds...because to THIS
            # host it's new (only in the cur_metric).  So we error out, the
            # inspector will use a debug message in the log.
            LOG.warning(
                'Unable to derive CPU Utilization for VM %s. It is '
                'either a new VM or was recently migrated. It will be '
                'collected in the next inspection cycle.', instance.name)
            return virt_inspector.InstanceStats(cpu_time=cpu_time,
                                                cpu_number=cpu_num)

        # Gather the previous metrics
        prev_util_cap = prev_metric.processor.util_cap_proc_cycles
        prev_util_uncap = prev_metric.processor.util_uncap_proc_cycles
        prev_idle = prev_metric.processor.idle_proc_cycles
        prev_donated = prev_metric.processor.donated_proc_cycles
        prev_entitled = prev_metric.processor.entitled_proc_cycles

        # Utilization can be driven by multiple factors on PowerVM.
        # PowerVM has 'entitled' cycles.  These are cycles that, if the VM
        # needs them, they get them no matter what.
        #
        # In terms of how those cycles are returned from the API:
        #   util_cap_proc_cycles - How many cycles from the guaranteed
        #          capacity were used.
        #   util_uncap_proc_cycles - How many cycles were used that were
        #          taken from spare (which is either unused processors cycles
        #          or donated cycles from other VMs).
        #   idle_proc_cycles - How many cycles (as reported by the OS to the
        #          hypervisor) were reported as idle.
        #   donated_proc_cycles - Cycles that were not needed by this VM that
        #          were given to another VM in need of cycles.
        #
        #
        # So the final utilization equation is:
        #   (util cap + util uncap - idle - donated) / entitled
        #
        # It is important to note that idle and donated proc cycles are
        # included in the 'util_cap_proc_cycles'.  That is why they are
        # subtracted out.
        #
        # The interesting aspect of this is that the CPU Utilization can go
        # dramatically above 100% if there are free processors or if the
        # other workloads are in a lull.
        util_cap = cur_util_cap - prev_util_cap
        util_uncap = cur_util_uncap - prev_util_uncap
        idle = cur_idle - prev_idle
        donated = cur_donated - prev_donated
        entitled = cur_entitled - prev_entitled

        # If the entitled is zero, that generally means that the VM has not
        # been started yet (everything else would be zero as well).  So to
        # avoid a divide by zero error, just return 0% in that case.
        util = (float(util_cap + util_uncap - idle - donated) /
                float(entitled) if entitled else 0.0)

        # Utilization is reported as percents.  Therefore, multiply by 100.0
        # to get a readable percentage based format.
        return virt_inspector.InstanceStats(cpu_util=util * 100.0,
                                            cpu_time=cpu_time,
                                            cpu_number=cpu_num)
Пример #11
0
    def inspect_disk_iops(self, instance, duration):
        """Inspect the Disk Input/Output operations per second for an instance.

        The response is a generator of the values.

        :param instance: the target instance
        :param duration: the last 'n' seconds, over which the value should be
               inspected.

               The PowerVM implementation does not make use of the duration
               field.
        :return disk: The Disk indicating the device for the storage device.
        :return stats: The DiskIOPSStats indicating the I/O operations per
                       second for the device.
        """
        # Get the current and previous sample.  Delta is performed between
        # these two.
        uuid = self._puuid(instance)
        cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid)
        prev_date, prev_metric = self.vm_metrics.get_previous_metric(uuid)

        # If the cur_metric is none, then the instance can not be found in the
        # sample and an error should be raised.
        if cur_metric is None:
            raise virt_inspector.InstanceNotFoundException(
                _('VM %s not found in PowerVM Metrics Sample.') %
                instance.name)

        # If there isn't storage information, this may be because the Virtual
        # I/O Metrics were turned off.  If the previous metric is unavailable,
        # also have to pass through this method.
        if (cur_metric.storage is None or prev_metric is None
                or prev_metric.storage is None):
            LOG.debug("Current storage metric was unavailable from the API "
                      "instance %s." % instance.name)
            return

        # Need to determine the time delta between the samples.  This is
        # usually 30 seconds from the API, but the metrics will be specific.
        # However, if there is no previous sample, then we have to estimate.
        # Therefore, we estimate 15 seconds - half of the standard 30 seconds.
        date_delta = ((cur_date - prev_date) if prev_date is not None else
                      datetime.timedelta(seconds=15))

        # Bundle together the SCSI and virtual FC adapters
        cur_adpts = (cur_metric.storage.virt_adpts +
                     cur_metric.storage.vfc_adpts)
        prev_adpts = (prev_metric.storage.virt_adpts +
                      prev_metric.storage.vfc_adpts)

        def find_prev(cur_adpt):
            for prev_adpt in prev_adpts:
                if prev_adpt.name == cur_adpt.name:
                    return prev_adpt
            return None

        # Loop through all the storage adapters
        for cur_adpt in cur_adpts:
            # IOPs is the read/write counts of the current - prev divided by
            # second difference between the two, rounded to the integer.  :-)
            cur_ops = cur_adpt.num_reads + cur_adpt.num_writes

            # The previous adapter may be None.  This simply indicates that the
            # adapter was added between the previous sample and this one.  It
            # does not indicate a live migrate scenario like noted above, as
            # the VM itself hasn't moved.
            prev_adpt = find_prev(cur_adpt)
            prev_ops = ((prev_adpt.num_reads +
                         prev_adpt.num_writes) if prev_adpt else 0)
            iops = (cur_ops - prev_ops) // date_delta.seconds

            # PowerVM only shows the connection (SCSI or FC).  Name after
            # the connection name
            yield virt_inspector.DiskIOPSStats(device=cur_adpt.name,
                                               iops_count=iops)
Пример #12
0
    def inspect_vnic_rates(self, instance, duration):
        """Inspect the vNIC rate statistics for an instance.

        :param instance: the target instance
        :param duration: the last 'n' seconds, over which the value should be
               inspected

               The PowerVM implementation does not make use of the duration
               field.
        :return: for each vNIC, the rate of bytes & packets
                 received and transmitted
        """
        # Get the current and previous sample.  Delta is performed between
        # these two.
        uuid = self._puuid(instance)
        cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid)
        prev_date, prev_metric = self.vm_metrics.get_previous_metric(uuid)

        # If the current is none, then the instance can not be found in the
        # sample and an error should be raised.
        if cur_metric is None:
            raise virt_inspector.InstanceNotFoundException(
                _('VM %s not found in PowerVM Metrics Sample.') %
                instance.name)

        # If there isn't network information, this is because the Virtual
        # I/O Metrics were turned off.  Have to pass through this method.
        if (cur_metric.network is None or prev_metric is None
                or prev_metric.network is None):
            return

        # Get the network interfaces.  A 'cna' is a Client VM's Network Adapter
        client_cnas = self._get_cnas(uuid)

        def find_prev_net(metric_cna):
            """Finds the metric vNIC from the previous sample's vNICs."""
            # If no previous, return None
            if prev_metric is None or prev_metric.network is None:
                return None

            for prev_cna in prev_metric.network.cnas:
                if prev_cna.physical_location == metric_cna.physical_location:
                    return prev_cna

            # Couldn't find a previous.  Maybe the interface was recently
            # added to the instance?  Return None
            return None

        # Need to determine the time delta between the samples.  This is
        # usually 30 seconds from the API, but the metrics will be specific.
        date_delta_num = float((cur_date - prev_date).seconds)

        for metric_cna in cur_metric.network.cnas:
            # Get the mac, but if it isn't found, then move to the next.  Might
            # have been removed since the last sample.
            mac = self.mac_for_metric_cna(metric_cna, client_cnas)
            if mac is None:
                continue

            # Note that here, the previous may be none.  That simply indicates
            # that the adapter was dynamically added to the VM before the
            # previous collection.  Not the migration scenario above.
            # In this case, we can default the base to 0.
            prev = find_prev_net(metric_cna)
            rx_bytes_diff = (metric_cna.received_bytes -
                             (0 if prev is None else prev.received_bytes))
            tx_bytes_diff = (metric_cna.sent_bytes -
                             (0 if prev is None else prev.sent_bytes))

            # Stats are the difference in the bytes, divided by the difference
            # in time between the two samples.
            rx_rate = float(rx_bytes_diff) / float(date_delta_num)
            tx_rate = float(tx_bytes_diff) / float(date_delta_num)

            # The name will be the location code.  MAC is identified from
            # above.  Others appear libvirt specific.
            yield virt_inspector.InterfaceRateStats(
                name=metric_cna.physical_location,
                mac=mac,
                fref=None,
                parameters=None,
                rx_bytes_rate=rx_rate,
                tx_bytes_rate=tx_rate)
Пример #13
0
    def inspect_disk_iops(self, instance):
        """Inspect the Disk Input/Output operations per second for an instance.

        The response is a generator of the values.

        :param instance: the target instance
        :return disk: The Disk indicating the device for the storage device.
        :return stats: The DiskIOPSStats indicating the I/O operations per
                       second for the device.
        """
        # Get the current and previous sample.  Delta is performed between
        # these two.
        uuid = self._puuid(instance)
        cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid)
        prev_date, prev_metric = self.vm_metrics.get_previous_metric(uuid)

        # If the cur_metric is none, then the instance can not be found in the
        # sample and an error should be raised.
        if cur_metric is None:
            raise virt_inspector.InstanceNotFoundException(
                _('VM %s not found in PowerVM Metrics Sample.') %
                instance.name)

        # If there isn't storage information, this may be because the Virtual
        # I/O Metrics were turned off.  If the previous metric is unavailable,
        # also have to pass through this method.
        if (cur_metric.storage is None or prev_metric is None or
                prev_metric.storage is None):
            LOG.debug("Current storage metric was unavailable from the API "
                      "instance %s." % instance.name)
            return

        # Need to determine the time delta between the samples.  This is
        # usually 30 seconds from the API, but the metrics will be specific.
        # However, if there is no previous sample, then we have to estimate.
        # Therefore, we estimate 15 seconds - half of the standard 30 seconds.
        date_delta = ((cur_date - prev_date) if prev_date is not None else
                      datetime.timedelta(seconds=15))

        # Bundle together the SCSI and virtual FC adapters
        cur_adpts = (cur_metric.storage.virt_adpts +
                     cur_metric.storage.vfc_adpts)
        prev_adpts = (prev_metric.storage.virt_adpts +
                      prev_metric.storage.vfc_adpts)

        def find_prev(cur_adpt):
            for prev_adpt in prev_adpts:
                if prev_adpt.name == cur_adpt.name:
                    return prev_adpt
            return None

        # Loop through all the storage adapters
        for cur_adpt in cur_adpts:
            # IOPs is the read/write counts of the current - prev divided by
            # second difference between the two, rounded to the integer.  :-)
            cur_ops = cur_adpt.num_reads + cur_adpt.num_writes

            # The previous adapter may be None.  This simply indicates that the
            # adapter was added between the previous sample and this one.  It
            # does not indicate a live migrate scenario like noted above, as
            # the VM itself hasn't moved.
            prev_adpt = find_prev(cur_adpt)
            prev_ops = ((prev_adpt.num_reads + prev_adpt.num_writes)
                        if prev_adpt else 0)
            iops = (cur_ops - prev_ops) // date_delta.seconds

            # PowerVM only shows the connection (SCSI or FC).  Name after
            # the connection name
            disk = virt_inspector.Disk(device=cur_adpt.name)
            stats = virt_inspector.DiskIOPSStats(iops_count=iops)
            yield (disk, stats)
Пример #14
0
    def inspect_vnic_rates(self, instance, duration=None):
        """Inspect the vNIC rate statistics for an instance.

        :param instance: the target instance
        :param duration: the last 'n' seconds, over which the value should be
               inspected

               The PowerVM implementation does not make use of the duration
               field.
        :return: for each vNIC, the rate of bytes & packets
                 received and transmitted
        """
        # Get the current and previous sample.  Delta is performed between
        # these two.
        uuid = self._puuid(instance)
        cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid)
        prev_date, prev_metric = self.vm_metrics.get_previous_metric(uuid)

        # If the current is none, then the instance can not be found in the
        # sample and an error should be raised.
        if cur_metric is None:
            raise virt_inspector.InstanceNotFoundException(
                _('VM %s not found in PowerVM Metrics Sample.') %
                instance.name)

        # If there isn't network information, this is because the Virtual
        # I/O Metrics were turned off.  Have to pass through this method.
        if (cur_metric.network is None or prev_metric is None or
                prev_metric.network is None):
            return

        # Get the network interfaces.  A 'cna' is a Client VM's Network Adapter
        client_cnas = self._get_cnas(uuid)

        def find_prev_net(metric_cna):
            """Finds the metric vNIC from the previous sample's vNICs."""
            # If no previous, return None
            if prev_metric is None or prev_metric.network is None:
                return None

            for prev_cna in prev_metric.network.cnas:
                if prev_cna.physical_location == metric_cna.physical_location:
                    return prev_cna

            # Couldn't find a previous.  Maybe the interface was recently
            # added to the instance?  Return None
            return None

        # Need to determine the time delta between the samples.  This is
        # usually 30 seconds from the API, but the metrics will be specific.
        date_delta_num = float((cur_date - prev_date).seconds)

        for metric_cna in cur_metric.network.cnas:
            # Get the mac, but if it isn't found, then move to the next.  Might
            # have been removed since the last sample.
            mac = self.mac_for_metric_cna(metric_cna, client_cnas)
            if mac is None:
                continue

            # The name will be the location code.  MAC is identified from
            # above.  Others appear libvirt specific.
            interface = virt_inspector.Interface(
                name=metric_cna.physical_location,
                mac=mac, fref=None, parameters=None)

            # Note that here, the previous may be none.  That simply indicates
            # that the adapter was dynamically added to the VM before the
            # previous collection.  Not the migration scenario above.
            # In this case, we can default the base to 0.
            prev = find_prev_net(metric_cna)
            rx_bytes_diff = (metric_cna.received_bytes -
                             (0 if prev is None else prev.received_bytes))
            tx_bytes_diff = (metric_cna.sent_bytes -
                             (0 if prev is None else prev.sent_bytes))

            # Stats are the difference in the bytes, divided by the difference
            # in time between the two samples.
            rx_rate = float(rx_bytes_diff) / float(date_delta_num)
            tx_rate = float(tx_bytes_diff) / float(date_delta_num)
            stats = virt_inspector.InterfaceRateStats(rx_rate, tx_rate)

            # Yield the results back to the invoker.
            yield (interface, stats)
Пример #15
0
    def inspect_cpu_util(self, instance, duration=None):
        """Inspect the CPU Utilization (%) for an instance.

        :param instance: the target instance
        :param duration: the last 'n' seconds, over which the value should be
               inspected.

               The PowerVM implementation does not make use of the duration
               field.
        :return: the percentage of CPU utilization
        """
        # The duration is ignored.  There is precedent for this in other
        # inspectors if the platform doesn't support duration.
        #
        # Given the nature of PowerVM to collect samples over coarse periods
        # of time, it does not lend well to duration based collection.
        # Therefore this works by gathering the latest utilization from the
        # samples and ignores the duration.

        # Get the current and previous sample.  Delta is performed between
        # these two.
        uuid = self._puuid(instance)
        cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid)
        prev_date, prev_metric = self.vm_metrics.get_previous_metric(uuid)

        # If the current is none, then the instance can not be found in the
        # sample and an error should be raised.
        if cur_metric is None:
            raise virt_inspector.InstanceNotFoundException(
                _('VM %s not found in PowerVM Metrics Sample.') %
                instance.name)

        # Get the current data.
        cur_util_cap = cur_metric.processor.util_cap_proc_cycles
        cur_util_uncap = cur_metric.processor.util_uncap_proc_cycles
        cur_idle = cur_metric.processor.idle_proc_cycles
        cur_donated = cur_metric.processor.donated_proc_cycles
        cur_entitled = cur_metric.processor.entitled_proc_cycles

        # Get the previous sample data
        if prev_metric is None:
            # If there is no previous sample, that is either a new VM or is
            # a live migrated system.  A live migrated system will pull all
            # of its metrics with it.  The issue with this is it could have
            # CPU cycles for months of run time.  So we can't really determine
            # the CPU utilization within the last X seconds...because to THIS
            # host its new (only in the cur_metric).  So we error out, the
            # inspector will use a debug message in the log.
            LOG.warn(_LW("Unable to derive CPU Utilization for VM %s.  It is "
                         "either a new VM or was recently migrated.  It will "
                         "be collected in the next inspection cycle."),
                     instance.name)
            message = (_("Unable to derive CPU Utilization for VM %s.") %
                       instance.name)
            raise virt_inspector.InstanceNotFoundException(message)

        # Gather the previous metrics
        prev_util_cap = prev_metric.processor.util_cap_proc_cycles
        prev_util_uncap = prev_metric.processor.util_uncap_proc_cycles
        prev_idle = prev_metric.processor.idle_proc_cycles
        prev_donated = prev_metric.processor.donated_proc_cycles
        prev_entitled = prev_metric.processor.entitled_proc_cycles

        # Utilization can be driven by multiple factors on PowerVM.
        # PowerVM has 'entitled' cycles.  These are cycles that, if the VM
        # needs them, they get them no matter what.
        #
        # In terms of how those cycles are returned from the API:
        #   util_cap_proc_cycles - How many cycles from the guaranteed
        #          capacity were used.
        #   util_uncap_proc_cycles - How many cycles were used that were
        #          taken from spare (which is either unused processors cycles
        #          or donated cycles from other VMs).
        #   idle_proc_cycles - How many cycles (as reported by the OS to the
        #          hypervisor) were reported as idle.
        #   donated_proc_cycles - Cycles that were not needed by this VM that
        #          were given to another VM in need of cycles.
        #
        #
        # So the final utilization equation is:
        #   (util cap + util uncap - idle - donated) / entitled
        #
        # It is important to note that idle and donated proc cycles are
        # included in the 'util_cap_proc_cycles'.  That is why they are
        # subtracted out.
        #
        # The interesting aspect of this is that the CPU Utilization can go
        # dramatically above 100% if there are free processors or if the
        # other workloads are in a lull.
        util_cap = cur_util_cap - prev_util_cap
        util_uncap = cur_util_uncap - prev_util_uncap
        idle = cur_idle - prev_idle
        donated = cur_donated - prev_donated
        entitled = cur_entitled - prev_entitled

        # If the entitled is zero, that generally means that the VM has not
        # been started yet (everything else would be zero as well).  So to
        # avoid a divide by zero error, just return 0% in that case.
        if entitled == 0:
            return virt_inspector.CPUUtilStats(util=0.0)

        util = float(util_cap + util_uncap - idle - donated) / float(entitled)

        # Utilization is reported as percents.  Therefore, multiply by 100.0
        # to get a readable percentage based format.
        return virt_inspector.CPUUtilStats(util=util * 100.0)