Esempio n. 1
0
 def setup(self):
     state = self.get_state()
     self.label = re.sub('.py$', '', os.path.basename(state['name']))
     self.browser = Browser("localhost", self.label)
     self.journal_start = re.sub(
         '.*cursor: ', '',
         subprocess.check_output(
             "journalctl --show-cursor -n0 -o cat || true", shell=True))
Esempio n. 2
0
 def setUp(self):
     #        state = self.get_state()
     self.label = ("avocado")
     self.browser = Browser("localhost", self.label)
     self.journal_start = re.sub(
         '.*cursor: ', '',
         subprocess.check_output(
             "journalctl --show-cursor -n0 -o cat || true", shell=True))
Esempio n. 3
0
class Test(test.Test):
    def __init__(self, **args):
        test.Test.__init__(self, **args)
        self.cleanup_funcs = []
        self.environment = imp.load_source(
            "",
            os.path.dirname(__file__) + "/lib/var.env")

    def atcleanup(self, func):
        self.cleanup_funcs.append(func)

    def run_shell_command(self, cmd, cleanup_cmd):
        self.atcleanup(lambda: process.run(cleanup_cmd, shell=True))
        process.run(cmd, shell=True)

    def replace_file(self, file, content):
        def restore():
            shutil.copyfile(file + ".cockpitsave", file)
            os.remove(file + ".cockpitsave")

        shutil.copyfile(file, file + ".cockpitsave")
        self.atcleanup(restore)
        with open(file, 'w') as f:
            f.write(content)

    def setup(self):
        state = self.get_state()
        self.label = re.sub('.py$', '', os.path.basename(state['name']))
        self.browser = Browser("localhost", self.label)
        self.journal_start = re.sub(
            '.*cursor: ', '',
            subprocess.check_output(
                "journalctl --show-cursor -n0 -o cat || true", shell=True))

    def action(self):
        process.run("systemctl start cockpit-testing.socket", shell=True)
        self.test()
        self.check_journal_messages()

    def cleanup(self):
        state = self.get_state()

        # Make a final screenshot and save the journal for the test run.
        #
        # TODO: Do this only when the test has failed.
        #
        self.browser.snapshot("DONE")
        process.run("journalctl >'%s.journal' -c'%s'" %
                    (self.label, self.journal_start),
                    shell=True)

        # If this is a remote run, copy all screenshots and journals
        # to the results directory so that they get copied out of the
        # virtual machine.
        #
        # The status of "cp" is ignored because it will fail when
        # there are no screenshots or journals, but that is not really
        # an error.
        #
        # TODO: Do this only once after running all tests.
        #
        if not state['job_logdir'].startswith("/tmp/"):
            process.run("cp -v *.png *.journal '%s'" % state['job_logdir'],
                        shell=True,
                        ignore_status=True)

        for f in self.cleanup_funcs:
            f()

        process.run(
            "systemctl stop cockpit-testing.socket cockpit-testing.service",
            shell=True)

    allowed_messages = [
        # This is a failed login, which happens every time
        "Returning error-response 401 with reason `Sorry'",

        # Reboots are ok
        "-- Reboot --",

        # Sometimes D-Bus goes away before us during shutdown
        "Lost the name com.redhat.Cockpit on the session message bus",
        "GLib-GIO:ERROR:gdbusobjectmanagerserver\\.c:.*:g_dbus_object_manager_server_emit_interfaces_.*: assertion failed \\(error == NULL\\): The connection is closed \\(g-io-error-quark, 18\\)",
        "Error sending message: The connection is closed",

        # Will go away with glib 2.43.2
        ".*: couldn't write web output: Error sending data: Connection reset by peer",

        ## Bugs

        # https://bugs.freedesktop.org/show_bug.cgi?id=70540
        ".*ActUserManager: user .* has no username.*",

        # https://github.com/cockpit-project/cockpit/issues/48
        "Failed to load '.*': Key file does not have group 'Unit'",

        # https://github.com/cockpit-project/cockpit/issues/115
        "cockpit-testing\\.service: main process exited, code=exited, status=1/FAILURE",
        "Unit cockpit-testing\\.service entered failed state\\.",

        # https://bugs.freedesktop.org/show_bug.cgi?id=71092
        "logind\\.KillUser failed \\(Input/output error\\), trying systemd\\.KillUnit",

        # SELinux messages to ignore
        "(audit: )?type=1403 audit.*",
        "(audit: )?type=1404 audit.*",

        # Hmm
        "request timed out, closing",
        "(audit: )?type=1400 .* name=\"machine-info\".*",
        "pam_lastlog\\(cockpit:session\\): unable to open /var/log/lastlog: No such file or directory"
    ]

    def allow_journal_messages(self, *patterns):
        """Don't fail if the journal containes a entry matching the given regexp"""
        for p in patterns:
            self.allowed_messages.append(p)

    def allow_restart_journal_messages(self):
        self.allow_journal_messages(
            "Error receiving data: Connection reset by peer",
            "g_dbus_connection_real_closed: Remote peer vanished with error: Underlying GIOStream returned 0 bytes on an async read \\(g-io-error-quark, 0\\). Exiting.",
            "g_dbus_connection_real_closed: Remote peer vanished with error: Error sending message: Broken pipe \\(g-io-error-quark, 44\\). Exiting.",
            # HACK: https://bugzilla.redhat.com/show_bug.cgi?id=1141137
            "localhost: bridge program failed: Child process killed by signal 9"
        )

    def journal_messages(self, syslog_ids, log_level):
        """Return interesting journal messages"""

        # Journald does not always set trusted fields like
        # _SYSTEMD_UNIT or _EXE correctly for the last few messages of
        # a dying process, so we filter by the untrusted but reliable
        # SYSLOG_IDENTIFIER instead

        matches = " ".join(
            map(lambda id: "SYSLOG_IDENTIFIER=" + id, syslog_ids))

        # Some versions of journalctl terminate unsuccessfully when
        # the output is empty.  We work around this by ignoring the
        # exit status and including error messages from journalctl
        # itself in the returned messages.

        cmd = "journalctl 2>&1 -c'%s' -o cat -p %d %s" % (self.journal_start,
                                                          log_level, matches)
        out = process.run(cmd, shell=True, ignore_status=True)
        messages = out.stdout.splitlines()
        if len(messages
               ) == 1 and "Cannot assign requested address" in messages[0]:
            # No messages
            return []
        else:
            return messages

    def audit_messages(self, type_pref):
        cmd = "journalctl -c'%s' -o cat SYSLOG_IDENTIFIER=kernel 2>&1 | grep 'type=%s.*audit' || true" % (
            self.journal_start, type_pref)
        out = process.run(cmd, shell=True)
        messages = out.stdout.splitlines()
        if len(messages
               ) == 1 and "Cannot assign requested address" in messages[0]:
            messages = []
        return messages

    def check_journal_messages(self):
        """Check for unexpected journal entries."""
        syslog_ids = ["cockpit-wrapper", "cockpit-ws", "cockpit-session"]
        messages = self.journal_messages(syslog_ids, 5)
        messages += self.audit_messages("14")  # 14xx is selinux
        all_found = True
        for m in messages:
            found = False
            for p in self.allowed_messages:
                match = re.match(p, m)
                if match and match.group(0) == m:
                    found = True
                    break
            if not found:
                self.log.info("Unexpected journal message '%s'" % m)
                all_found = False
        self.assertTrue(all_found,
                        msg="There were unexpected journal messages")
Esempio n. 4
0
 def setup(self):
     state = self.get_state()
     self.label = re.sub('.py$', '', os.path.basename(state['name']))
     self.browser = Browser("localhost", self.label)
     self.journal_start = re.sub('.*cursor: ', '',
                                 subprocess.check_output("journalctl --show-cursor -n0 -o cat || true", shell=True))
Esempio n. 5
0
class Test(test.Test):
    def __init__(self, **args):
        test.Test.__init__(self, **args)
        self.cleanup_funcs = [ ]
        self.environment = imp.load_source("", os.path.dirname(__file__) + "/lib/var.env")

    def atcleanup(self, func):
        self.cleanup_funcs.append(func)

    def run_shell_command(self, cmd, cleanup_cmd):
        self.atcleanup(lambda: process.run(cleanup_cmd, shell=True))
        process.run(cmd, shell=True)

    def replace_file(self, file, content):
        def restore():
            shutil.copyfile(file + ".cockpitsave", file)
            os.remove(file + ".cockpitsave")
        shutil.copyfile(file, file + ".cockpitsave")
        self.atcleanup(restore)
        with open(file, 'w') as f: f.write(content)

    def setup(self):
        state = self.get_state()
        self.label = re.sub('.py$', '', os.path.basename(state['name']))
        self.browser = Browser("localhost", self.label)
        self.journal_start = re.sub('.*cursor: ', '',
                                    subprocess.check_output("journalctl --show-cursor -n0 -o cat || true", shell=True))

    def action(self):
        process.run("systemctl start cockpit-testing.socket", shell=True)
        self.test()
        self.check_journal_messages()

    def cleanup(self):
        state = self.get_state()

        # Make a final screenshot and save the journal for the test run.
        #
        # TODO: Do this only when the test has failed.
        #
        self.browser.snapshot("DONE")
        process.run("journalctl >'%s.journal' -c'%s'" % (self.label, self.journal_start), shell=True)

        # If this is a remote run, copy all screenshots and journals
        # to the results directory so that they get copied out of the
        # virtual machine.
        #
        # The status of "cp" is ignored because it will fail when
        # there are no screenshots or journals, but that is not really
        # an error.
        #
        # TODO: Do this only once after running all tests.
        #
        if not state['job_logdir'].startswith("/tmp/"):
            process.run("cp -v *.png *.journal '%s'" %  state['job_logdir'],
                        shell=True, ignore_status=True)

        for f in self.cleanup_funcs: f()

        process.run("systemctl stop cockpit-testing.socket cockpit-testing.service", shell=True)

    allowed_messages = [
        # This is a failed login, which happens every time
        "Returning error-response 401 with reason `Sorry'",

        # Reboots are ok
        "-- Reboot --",

        # Sometimes D-Bus goes away before us during shutdown
        "Lost the name com.redhat.Cockpit on the session message bus",
        "GLib-GIO:ERROR:gdbusobjectmanagerserver\\.c:.*:g_dbus_object_manager_server_emit_interfaces_.*: assertion failed \\(error == NULL\\): The connection is closed \\(g-io-error-quark, 18\\)",
        "Error sending message: The connection is closed",

        # Will go away with glib 2.43.2
        ".*: couldn't write web output: Error sending data: Connection reset by peer",

        ## Bugs

        # https://bugs.freedesktop.org/show_bug.cgi?id=70540
        ".*ActUserManager: user .* has no username.*",

        # https://github.com/cockpit-project/cockpit/issues/48
        "Failed to load '.*': Key file does not have group 'Unit'",

        # https://github.com/cockpit-project/cockpit/issues/115
        "cockpit-testing\\.service: main process exited, code=exited, status=1/FAILURE",
        "Unit cockpit-testing\\.service entered failed state\\.",

        # https://bugs.freedesktop.org/show_bug.cgi?id=71092
        "logind\\.KillUser failed \\(Input/output error\\), trying systemd\\.KillUnit",

        # SELinux messages to ignore
        "(audit: )?type=1403 audit.*",
        "(audit: )?type=1404 audit.*",

        # Hmm
        "request timed out, closing",
        "(audit: )?type=1400 .* name=\"machine-info\".*",
        "pam_lastlog\\(cockpit:session\\): unable to open /var/log/lastlog: No such file or directory"
    ]

    def allow_journal_messages(self, *patterns):
        """Don't fail if the journal containes a entry matching the given regexp"""
        for p in patterns:
            self.allowed_messages.append(p)

    def allow_restart_journal_messages(self):
        self.allow_journal_messages("Error receiving data: Connection reset by peer",
                                    "g_dbus_connection_real_closed: Remote peer vanished with error: Underlying GIOStream returned 0 bytes on an async read \\(g-io-error-quark, 0\\). Exiting.",
                                    "g_dbus_connection_real_closed: Remote peer vanished with error: Error sending message: Broken pipe \\(g-io-error-quark, 44\\). Exiting.",
                                    # HACK: https://bugzilla.redhat.com/show_bug.cgi?id=1141137
                                    "localhost: bridge program failed: Child process killed by signal 9")

    def journal_messages(self, syslog_ids, log_level):
        """Return interesting journal messages"""

        # Journald does not always set trusted fields like
        # _SYSTEMD_UNIT or _EXE correctly for the last few messages of
        # a dying process, so we filter by the untrusted but reliable
        # SYSLOG_IDENTIFIER instead

        matches = " ".join(map(lambda id: "SYSLOG_IDENTIFIER=" + id, syslog_ids))

        # Some versions of journalctl terminate unsuccessfully when
        # the output is empty.  We work around this by ignoring the
        # exit status and including error messages from journalctl
        # itself in the returned messages.

        cmd = "journalctl 2>&1 -c'%s' -o cat -p %d %s" % (self.journal_start, log_level, matches)
        out = process.run(cmd, shell=True, ignore_status=True)
        messages = out.stdout.splitlines()
        if len(messages) == 1 and "Cannot assign requested address" in messages[0]:
            # No messages
            return [ ]
        else:
            return messages

    def audit_messages(self, type_pref):
        cmd = "journalctl -c'%s' -o cat SYSLOG_IDENTIFIER=kernel 2>&1 | grep 'type=%s.*audit' || true" % (self.journal_start, type_pref)
        out = process.run(cmd, shell=True)
        messages = out.stdout.splitlines()
        if len(messages) == 1 and "Cannot assign requested address" in messages[0]:
            messages = [ ]
        return messages

    def check_journal_messages(self):
        """Check for unexpected journal entries."""
        syslog_ids = [ "cockpit-wrapper", "cockpit-ws", "cockpit-session" ]
        messages = self.journal_messages(syslog_ids, 5)
        messages += self.audit_messages("14") # 14xx is selinux
        all_found = True
        for m in messages:
            found = False
            for p in self.allowed_messages:
                match = re.match(p, m)
                if match and match.group(0) == m:
                    found = True
                    break
            if not found:
                self.log.info("Unexpected journal message '%s'" % m)
                all_found = False
        self.assertTrue(all_found, msg="There were unexpected journal messages")