Ejemplo n.º 1
0
 def test_execute_nowait(self):
     bu.execute(self.some_command_with_args, False)
     self.assertTrue(self.popen.mock.popen.called)
     self.popen.mock.popen.assert_call(self.some_command_with_args)
     self.assertFalse(self.popen.mock.communicate.called)
Ejemplo n.º 2
0
    def test_execute_error(self):
        self.popen.mock.returncode = 1

        with self.assertRaises(RuntimeError):
            bu.execute(self.some_command_with_args)
Ejemplo n.º 3
0
    def _update_widgets(self, widgets):
        zfs_version_path = "/sys/module/zfs/version"
        # zpool list -H: List all zpools, use script mode (no headers and tabs as separators).
        try:
            with open(zfs_version_path, 'r') as zfs_mod_version:
                zfs_version = zfs_mod_version.readline().rstrip().split('-')[0]
        except IOError:
            # ZFS isn't installed or the module isn't loaded, stub the version
            zfs_version = "0.0.0"
            logging.error(
                "ZFS version information not found at {}, check the module is loaded."
                .format(zfs_version_path))

        raw_zpools = execute(('sudo ' if self._usesudo else '') +
                             'zpool list -H').split('\n')

        for widget in widgets:
            widget.set("visited", False)

        for raw_zpool in raw_zpools:
            try:
                # Ignored fields (assigned to _) are "expandsz" and "altroot", also "ckpoint" in ZFS 0.8.0+
                if parse_version(zfs_version) < parse_version("0.8.0"):
                    name, size, alloc, free, _, frag, cap, dedup, health, _ = raw_zpool.split(
                        '\t')
                else:
                    name, size, alloc, free, _, _, frag, cap, dedup, health, _ = raw_zpool.split(
                        '\t')
                cap = cap.rstrip('%')
                percentuse = int(cap)
                percentfree = 100 - percentuse
                # There is a command, zpool iostat, which is however blocking and was therefore
                # causing issues.
                # Instead, we read file `/proc/spl/kstat/zfs/<poolname>/io` which contains
                # cumulative I/O statistics since boot (or pool creation). We store these values
                # (and timestamp) during each widget update, and during the next widget update we
                # use them to compute delta of transferred bytes, and using the last and current
                # timestamp the rate at which they have been transferred.
                with open("/proc/spl/kstat/zfs/{}/io".format(name), "r") as f:
                    # Third row provides data we need, we are interested in the first 4 values.
                    # More info about this file can be found here:
                    # https://github.com/zfsonlinux/zfs/blob/master/lib/libspl/include/sys/kstat.h#L580
                    # The 4 values are:
                    # nread, nwritten, reads, writes
                    iostat = list(map(int, f.readlines()[2].split()[:4]))
            except (ValueError, IOError):
                # Unable to parse info about this pool, skip it
                continue

            if self._includelist and name not in self._includelist:
                continue

            widget = self.widget(name)
            if not widget:
                widget = bumblebee.output.Widget(name=name)
                widget.set("last_iostat", [0, 0, 0, 0])
                widget.set("last_timestamp", 0)
                widgets.append(widget)

            delta_iostat = [
                b - a for a, b in zip(iostat, widget.get("last_iostat"))
            ]
            widget.set("last_iostat", iostat)

            # From docs:
            #   > Note that even though the time is always returned as a floating point number, not
            #   > all systems provide time with a better precision than 1 second.
            # Be aware that that may affect the precision of reported I/O
            # Also, during one update cycle the reported I/O may be garbage if the system time
            # was changed.
            timestamp = time.time()
            delta_timestamp = widget.get("last_timestamp") - timestamp
            widget.set("last_timestamp", time.time())

            # abs is there because sometimes the result is -0
            rate_iostat = [abs(x / delta_timestamp) for x in delta_iostat]
            nread, nwritten, reads, writes = rate_iostat

            # theme.minwidth is not set since these values are not expected to change
            # rapidly
            widget.full_text(
                self._format.format(name=name,
                                    used=alloc,
                                    left=free,
                                    size=size,
                                    percentfree=percentfree,
                                    percentuse=percentuse,
                                    status=health,
                                    shortstatus=self._shortstatus(health),
                                    fragpercent=frag,
                                    deduppercent=dedup))
            widget.set("state", health)
            widget.set("percentfree", percentfree)
            widget.set("visited", True)

            if self._showio:
                wname, rname = [name + x for x in ["__write", "__read"]]
                widget_w = self.widget(wname)
                widget_r = self.widget(rname)
                if not widget_w or not widget_r:
                    widget_r = bumblebee.output.Widget(name=rname)
                    widget_w = bumblebee.output.Widget(name=wname)
                    widgets.extend([widget_r, widget_w])
                for w in [widget_r, widget_w]:
                    w.set(
                        "theme.minwidth",
                        self._ioformat.format(ops=9999,
                                              band=bytefmt(999.99 *
                                                           (1024**2))))
                    w.set("visited", True)
                widget_w.full_text(
                    self._ioformat.format(ops=round(writes),
                                          band=bytefmt(nwritten)))
                widget_r.full_text(
                    self._ioformat.format(ops=round(reads),
                                          band=bytefmt(nread)))

        for widget in widgets:
            if widget.get("visited") is False:
                widgets.remove(widget)