Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package cockpit for openSUSE:Factory checked in at 2022-09-16 13:32:05 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/cockpit (Old) and /work/SRC/openSUSE:Factory/.cockpit.new.2083 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "cockpit" Fri Sep 16 13:32:05 2022 rev:24 rq:1003842 version:271 Changes: -------- --- /work/SRC/openSUSE:Factory/cockpit/cockpit.changes 2022-08-26 09:07:57.505364170 +0200 +++ /work/SRC/openSUSE:Factory/.cockpit.new.2083/cockpit.changes 2022-09-16 13:32:28.573294955 +0200 @@ -1,0 +2,18 @@ +Tue Sep 13 09:46:17 UTC 2022 - Adam Majer <[email protected]> + +- Fix cockpit-storage dependencies +- Merge SUSE branding into cockpit package + +------------------------------------------------------------------- +Mon Sep 5 08:09:56 UTC 2022 - Jacek Tomasiak <[email protected]> + +- Update kdump-suse.patch to match upstream. + +------------------------------------------------------------------- +Wed Aug 24 12:25:42 UTC 2022 - Jacek Tomasiak <[email protected]> + +- Add kdump-close.patch required by patches below. +- Add kdump-refactor.patch and kdump-suse.patch to support SUSE + kdump config management in cockpit. + +------------------------------------------------------------------- New: ---- cockpit-suse-theme.obscpio cockpit-suse-theme.obsinfo kdump-close.patch kdump-refactor.patch kdump-suse.patch ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ cockpit.spec ++++++ --- /var/tmp/diff_new_pack.cEsjmH/_old 2022-09-16 13:32:30.321300602 +0200 +++ /var/tmp/diff_new_pack.cEsjmH/_new 2022-09-16 13:32:30.345300680 +0200 @@ -55,6 +55,7 @@ Source0: cockpit-%{version}.tar Source1: cockpit.pam Source2: cockpit-rpmlintrc +Source3: cockpit-suse-theme.tar Source99: README.packaging Source98: package-lock.json Source97: node_modules.spec.inc @@ -64,6 +65,9 @@ Patch3: suse-microos-branding.patch Patch4: css-overrides.patch Patch5: storage-btrfs.patch +Patch6: kdump-close.patch +Patch7: kdump-refactor.patch +Patch8: kdump-suse.patch # SLE Micro specific patches Patch100: remove-pwscore.patch Patch101: hide-pcp.patch @@ -179,12 +183,15 @@ %endif %prep -%setup -q -n cockpit-%{version} +%setup -q -n cockpit-%{version} -a 3 %patch1 -p1 %patch2 -p1 %patch3 -p1 %patch4 -p1 %patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 %if 0%{?sle_version} %patch100 -p1 @@ -230,6 +237,13 @@ rm -f %{buildroot}/%{_libdir}/cockpit/*.so install -D -p -m 644 AUTHORS COPYING README.md %{buildroot}%{_docdir}/cockpit/ +mkdir -p %{buildroot}%{_datadir}/cockpit/branding/suse +pushd cockpit-suse-theme +cp src/css-overrides.css %{buildroot}%{_datadir}/cockpit/branding/suse +cp src/fonts.css %{buildroot}%{_datadir}/cockpit/branding/suse +cp -a src/fonts %{buildroot}%{_datadir}/cockpit/branding/suse +popd + # only ship deprecated PatternFly API for stable releases %if 0%{?rhel} == 8 if [ -f %{buildroot}/%{_datadir}/cockpit/base1/cockpit.css.gz ]; then @@ -343,7 +357,7 @@ # remove brandings with stale symlinks. Means they don't match # the distro. pushd %{buildroot}/%{_datadir}/cockpit/branding -ls --hide={default,kubernetes,opensuse,registry,sle-micro} | xargs rm -rv +ls --hide={default,kubernetes,opensuse,registry,sle-micro,suse} | xargs rm -rv popd # need this in SUSE as post build checks dislike stale symlinks install -m 644 -D /dev/null %{buildroot}/run/cockpit/motd @@ -697,14 +711,16 @@ Summary: Cockpit user interface for storage, using udisks Requires: cockpit-shell >= 266 Requires: udisks2 >= 2.9 -Recommends: udisks2-lvm2 >= 2.9 -Recommends: udisks2-iscsi >= 2.9 -Recommends: device-mapper-multipath -Recommends: clevis-luks Requires: %{__python3} %if 0%{?suse_version} +Requires: libudisks2-0_lvm2 >= 2.9 +Recommends: multipath-tools Requires: python3-dbus-python %else +Recommends: udisks2-lvm2 >= 2.9 +Recommends: udisks2-iscsi >= 2.9 +Recommends: device-mapper-multipath +Recommends: clevis-luks Requires: python3-dbus %endif BuildArch: noarch ++++++ _service ++++++ --- /var/tmp/diff_new_pack.cEsjmH/_old 2022-09-16 13:32:30.413300900 +0200 +++ /var/tmp/diff_new_pack.cEsjmH/_new 2022-09-16 13:32:30.417300912 +0200 @@ -1,5 +1,15 @@ <services> <service name="obs_scm" mode="manual"> + <param name="url">https://github.com/dgdavid/cockpit-suse-theme.git</param> + <param name="versionformat"></param> + <param name="scm">git</param> + <param name="revision">main</param> + </service> + <service mode="buildtime" name="tar"> + <param name="obsinfo">cockpit-suse-theme.obsinfo</param> + </service> + + <service name="obs_scm" mode="manual"> <param name="versionformat">@PARENT_TAG@</param> <param name="url">http://github.com/cockpit-project/cockpit.git</param> <param name="scm">git</param> @@ -17,5 +27,7 @@ <service mode="buildtime" name="set_version"> <param name="basename">cockpit</param> </service> + + </services> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.cEsjmH/_old 2022-09-16 13:32:30.437300977 +0200 +++ /var/tmp/diff_new_pack.cEsjmH/_new 2022-09-16 13:32:30.441300990 +0200 @@ -1,6 +1,8 @@ <servicedata> <service name="tar_scm"> <param name="url">http://github.com/cockpit-project/cockpit.git</param> - <param name="changesrevision">046b3d4b381cd60f9d44756fc51f15ed7e17d0b5</param></service></servicedata> + <param name="changesrevision">046b3d4b381cd60f9d44756fc51f15ed7e17d0b5</param></service><service name="tar_scm"> + <param name="url">https://github.com/dgdavid/cockpit-suse-theme.git</param> + <param name="changesrevision">fe08b35e64ad45f4b56cd636fdfec8fb18d69ab7</param></service></servicedata> (No newline at EOF) ++++++ cockpit-suse-theme.obsinfo ++++++ name: cockpit-suse-theme version: mtime: 1655379139 commit: fe08b35e64ad45f4b56cd636fdfec8fb18d69ab7 ++++++ kdump-close.patch ++++++ >From 9be51b563c98744053e4a7412e5030fa2ab3e061 Mon Sep 17 00:00:00 2001 From: Marius Vollmer <[email protected]> Date: Mon, 8 Aug 2022 14:50:51 +0300 Subject: [PATCH] kdump: Use close with cockpit.file, not remove There is no remove, and the intention is to close the watch channel. --- pkg/kdump/config-client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/kdump/config-client.js b/pkg/kdump/config-client.js index 9b95b9a0c65..c58cb85fd99 100644 --- a/pkg/kdump/config-client.js +++ b/pkg/kdump/config-client.js @@ -47,7 +47,7 @@ export class ConfigFile { close() { if (this._fileHandle) { - this._fileHandle.remove(); + this._fileHandle.close(); this._fileHandle = undefined; } } ++++++ kdump-refactor.patch ++++++ ++++ 713 lines (skipped) ++++++ kdump-suse.patch ++++++ >From d95850239f81a65c90743f20a0bc0450cb61823a Mon Sep 17 00:00:00 2001 From: Jacek Tomasiak <[email protected]> Date: Fri, 2 Sep 2022 16:51:02 +0200 Subject: [PATCH] kdump: Add SUSE kdump config support If parsing /etc/kdump.conf doesn't return usable settings, try /etc/sysconfig/kdump which is used by SUSE distributions as the main kdump config. The file is in dotenv format and currently only KDUMP_SAVEDIR, KDUMP_DUMPFORMAT and KDUMP_SSH_IDENTITY entries are used by Cockpit. SUSE supports additional dump target types (ftp, sftp, cifs) but doesn't support others (raw, mount). The target dialog currently supports the common types (nfs, ssh, local). --- pkg/kdump/config-client-suse.js | 265 ++++++++++++++++++++++++++++++++ pkg/kdump/kdump-client.js | 14 ++ pkg/kdump/kdump-view.jsx | 8 +- test/verify/check-kdump | 127 +++++++++++++++ 4 files changed, 413 insertions(+), 1 deletion(-) create mode 100644 pkg/kdump/config-client-suse.js diff --git a/pkg/kdump/config-client-suse.js b/pkg/kdump/config-client-suse.js new file mode 100644 index 00000000000..074d9e406ca --- /dev/null +++ b/pkg/kdump/config-client-suse.js @@ -0,0 +1,265 @@ +/* + * This file is part of Cockpit. + * + * Copyright (C) 2022 SUSE LLC + * + * Cockpit is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * Cockpit is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Cockpit; If not, see <http://www.gnu.org/licenses/>. + */ + +import { ConfigFile } from './config-client.js'; + +/* Parse an dotenv-style config file + * and monitor it for changes + */ +export class ConfigFileSUSE extends ConfigFile { + /* parse lines of the config file + * if a line has a valid key=value format, use the key in _internal structure + * and also store original line, line index, value and optional line suffix / comment + * if value was quoted it will be stripped of quotes in `value` and `quoted` flag will + * be used when writing the file to keep original formatting + * e.g. for line 'someKey="foo" # comment' + * outputObject._internal["someKey"] = { + * index: 0, + * value: "foo", + * quoted: true, + * origLine: 'someKey="foo" # comment', + * suffix: "# comment" + * } + * skipNotify: Don't notify about changes, e.g.to avoid multiple updates when writing a file + */ + _parseText(rawContent, skipNotify = false) { + this._dataAvailableResolve(); + + // clear settings if file is empty/missing + if (!rawContent) { + this._originalSettings = null; + this.settings = null; + if (!skipNotify) + this.dispatchEvent("kdumpConfigChanged", this.settings); + return; + } + + // if nothing changed, don't bother parsing the content + if (rawContent == this._rawContent) + return; + + this._rawContent = rawContent; + + // this is the format expected by the UI + this.settings = { + _internal: {}, + targets: {}, + compression: { enabled: false, allowed: true }, + }; + + this._lines = rawContent.split(/\r?\n/); + this._lines.forEach((line, index) => { + const trimmed = line.trim(); + // if the line is empty or only a comment, skip + if (trimmed.indexOf("#") === 0 || trimmed.length === 0) + return; + + // parse KEY=value or KEY="value" line + let parts = trimmed.match(/^([A-Z_]+)\s*=\s*(.*)$/); + if (parts === null) { + console.warn("Malformed kdump config line:", trimmed, "in", this.filename); + return; + } + const key = parts[1]; + let value = parts[2]; + + // value might be quoted + let quoted = false; + if (value.startsWith('"')) { + quoted = true; + parts = value.match(/^"([^"]*)"\s*(.*)$/); + // malformed line, no ending quote? + if (parts === null) { + console.warn("Incorrectly quoted value in kdump config line:", line, "in", this.filename); + return; + } + } else { + // not quoted should be simple value but grab everything and quote on write + parts = value.match(/^([^#]+?)\s*(#.*)?$/); + if (parts === null) + parts = ["", ""]; + } + value = parts[1]; + const suffix = (parts[2] || "").trim(); + + this.settings._internal[key] = { + index: index, + value: value, + origLine: line, + quoted: quoted, + suffix: suffix + }; + }); + + // make sure we copy the original keys so we overwrite the correct lines when saving + this._originalSettings = { }; + Object.keys(this.settings._internal).forEach((key) => { + this._originalSettings[key] = { ...this.settings._internal[key] }; + }); + + this._extractSettings(); + + if (!skipNotify) + this.dispatchEvent("kdumpConfigChanged", this.settings); + } + + /* extract settings managed by cockpit from _internal into platform independent model + */ + _extractSettings() { + // generate target(s) from KDUMP_SAVEDIR + if ("KDUMP_SAVEDIR" in this.settings._internal && this.settings._internal.KDUMP_SAVEDIR.value) { + let savedir = this.settings._internal.KDUMP_SAVEDIR.value; + // handle legacy "file" without prefix + if (savedir.startsWith("/")) + savedir = "file://" + savedir; + // server includes "username:password@" and can be empty for file:// + const parts = savedir.match(/^(.*):\/\/([^/]*)(\/.*)$/); + // malformed KDUMP_SAVEDIR + if (parts === null) { + console.warn("Malformed KDUMP_SAVEDIR entry:", savedir, "in", this.filename); + return; + } + const [, scheme, server, path] = parts; + if (scheme === "file") { + this.settings.targets.local = { + type: "local", + path: path, + }; + } else if (scheme === "nfs") { + this.settings.targets.nfs = { + type: scheme, + // on read full path is used as export + export: path, + server: server, + }; + } else { + this.settings.targets[scheme] = { + type: scheme, + path: path, + server: server, + }; + // sshkey is used by ssh and sftp/scp + if ("KDUMP_SSH_IDENTITY" in this.settings._internal) { + this.settings.targets[scheme].sshkey = + this.settings._internal.KDUMP_SSH_IDENTITY.value; + } + } + } + + // default to local if no target configured + if (Object.keys(this.settings.targets).length === 0) + this.settings.targets.local = { type: "local" }; + + this.settings.compression.enabled = ( + !("KDUMP_DUMPFORMAT" in this.settings._internal) || + // TODO: what about other compression formats (lzo, snappy)? + this.settings._internal.KDUMP_DUMPFORMAT.value === "compressed" + ); + } + + /* update single _internal setting to given value + * make sure setting exists if value is not empty + * don't delete existing settings + */ + _updateSetting(settings, key, value) { + if (key in settings._internal) { + settings._internal[key].value = value; + } else { + if (value) + settings._internal[key] = { value: value }; + } + } + + /* transform settings from model back to _internal format + * this.settings = current state from file + * settings = in-memory state from UI + */ + _persistSettings(settings) { + // target + if (Object.keys(settings.targets).length > 0) { + const target = Object.values(settings.targets)[0]; + + if ("sshkey" in target) + this._updateSetting(settings, "KDUMP_SSH_IDENTITY", target.sshkey); + + let savedir; + // default for empty path (except nfs, see below) + let path = target.path || "/var/crash"; + if (path && !path.startsWith("/")) + path = "/" + path; + if (target.type === "local") { + savedir = "file://" + path; + } else if (target.type === "nfs") { + // override empty path default as nfs path is merged into export on read + if (!target.path) + path = ""; + let exprt = target.export; + if (!exprt.startsWith("/")) + exprt = "/" + exprt; + savedir = "nfs://" + target.server + exprt + path; + } else { + savedir = target.type + "://" + target.server + path; + } + this._updateSetting(settings, "KDUMP_SAVEDIR", savedir); + } + // compression + if (this.settings.compression.enabled != settings.compression.enabled) { + if (settings.compression.enabled) { + this._updateSetting(settings, "KDUMP_DUMPFORMAT", "compressed"); + } else { + this._updateSetting(settings, "KDUMP_DUMPFORMAT", "ELF"); + } + } + return settings; + } + + /* generate the config file from raw text and settings + */ + _generateConfig(settings) { + settings = this._persistSettings(settings); + + const lines = this._lines.slice(0); + + // we take the lines from our last read operation and modify them with the new settings + Object.keys(settings._internal).forEach((key) => { + const entry = settings._internal[key]; + + let value = entry.value !== undefined ? entry.value : ""; + // quote what was quoted before + empty values + multi-word values + if (entry.quoted || value === "" || value.includes(" ")) + value = '"' + value + '"'; + let line = key + "=" + value; + if (entry.suffix) + line = line + " " + entry.suffix; + // this might be a new entry + if (!(key in this._originalSettings)) { + lines.push(line); + return; + } + // otherwise edit the old line + const origEntry = this._originalSettings[key]; + lines[origEntry.index] = line; + }); + + // make sure file ends with a newline + if (lines[lines.length - 1] !== "") + lines.push(""); + return lines.join("\n"); + } +} diff --git a/pkg/kdump/kdump-client.js b/pkg/kdump/kdump-client.js index d001ebb0b5a..7af24dc1bcb 100644 --- a/pkg/kdump/kdump-client.js +++ b/pkg/kdump/kdump-client.js @@ -20,6 +20,7 @@ import cockpit from 'cockpit'; import { proxy as serviceProxy } from 'service'; import { ConfigFile } from './config-client.js'; +import { ConfigFileSUSE } from './config-client-suse.js'; import crashKernelScript from 'raw-loader!./crashkernel.sh'; import testWritableScript from 'raw-loader!./testwritable.sh'; @@ -61,6 +62,19 @@ export class KdumpClient { // watch the config file this.configClient = new ConfigFile("/etc/kdump.conf", true); + this._watchConfigChanges(); + + this.configClient.wait().then(() => { + // if no configuration found, try SUSE version + if (this.configClient.settings === null) { + this.configClient.close(); + this.configClient = new ConfigFileSUSE("/etc/sysconfig/kdump", true); + this._watchConfigChanges(); + } + }); + } + + _watchConfigChanges() { // catch config changes this.configClient.addEventListener('kdumpConfigChanged', () => { this.state.config = this.configClient.settings; diff --git a/pkg/kdump/kdump-view.jsx b/pkg/kdump/kdump-view.jsx index 956811d7826..3de3761706b 100644 --- a/pkg/kdump/kdump-view.jsx +++ b/pkg/kdump/kdump-view.jsx @@ -364,6 +364,12 @@ export class KdumpPage extends React.Component { /* mount targets outside of nfs are too complex for the * current target dialog */ kdumpLocation = _("On a mounted device"); + } else if (target.type == "ftp") { + kdumpLocation = _("Remote over FTP"); + } else if (target.type == "sftp") { + kdumpLocation = _("Remote over SFTP"); + } else if (target.type == "cifs") { + kdumpLocation = _("Remote over CIFS/SMB"); } else { kdumpLocation = _("No configuration found"); } @@ -372,7 +378,7 @@ export class KdumpPage extends React.Component { // this.storeLocation(this.props.kdumpStatus.config); const settingsLink = targetCanChange ? <Button variant="link" isInline id="kdump-change-target" onClick={this.handleSettingsClick}>{ kdumpLocation }</Button> - : <span>{ kdumpLocation }</span>; + : <span id="kdump-target-info">{ kdumpLocation }</span>; let reservedMemory; if (this.props.reservedMemory === undefined) { // still waiting for result diff --git a/test/verify/check-kdump b/test/verify/check-kdump index 03d9a199970..855636eb0da 100755 --- a/test/verify/check-kdump +++ b/test/verify/check-kdump @@ -248,6 +248,133 @@ class TestKdump(KdumpHelpers): conf = m.execute("cat /etc/kdump.conf") self.assertIn(current + " -c", conf) + @nondestructive + def testConfigurationSUSE(self): + b = self.browser + m = self.machine + + testConfig = [ + "# some comment", + "KDUMP_DUMPFORMAT=compressed # suffix", + "KDUMP_SSH_IDENTITY=\"\"", + "skip this line", + "BAD_QUOTES=unquoted value # suffix", + "BAD_SPACES = 42 # comment", + "MORE_BAD_SPACES = 4 2 # long comment", + "KDUMP_SAVEDIR=ssh//missing/colon", + ] + + # clean default config to trigger SUSE config mode + self.write_file("/etc/kdump.conf", "") + # write initial SUSE config (append to keep original contents as well) + self.write_file("/etc/sysconfig/kdump", "\n".join(testConfig), append=True) + + m.execute("systemctl disable --now kdump") + + self.login_and_go("/kdump") + b.wait_visible("#app") + + # Check malformed lines + b.wait_text("#kdump-target-info", "No configuration found") + b.wait(lambda: "warning: Malformed kdump config line: skip this line in /etc/sysconfig/kdump" in list(self.browser.get_js_log())) + b.wait(lambda: "warning: Malformed KDUMP_SAVEDIR entry: ssh//missing/colon in /etc/sysconfig/kdump" in list(self.browser.get_js_log())) + + # Remove malformed KDUMP_SAVEDIR to check default if nothing specified + m.execute("sed -i '/KDUMP_SAVEDIR=.*/d' /etc/sysconfig/kdump") + b.wait_text("#kdump-change-target", "locally in /var/crash") + + # Check fixing of (some) malformed lines and local target without file:// + m.execute("echo KDUMP_SAVEDIR=/tmp >> /etc/sysconfig/kdump") + b.wait_text("#kdump-change-target", "locally in /tmp") + b.click("#kdump-change-target") + b.wait_visible("#kdump-settings-dialog") + b.click("button:contains('Save')") + b.wait_not_present("#kdump-settings-dialog") + conf = m.execute("cat /etc/sysconfig/kdump") + self.assertIn('KDUMP_SAVEDIR=file:///tmp', conf) + self.assertIn('BAD_QUOTES="unquoted value" # suffix', conf) + self.assertIn('BAD_SPACES=42 # comment', conf) + self.assertIn('MORE_BAD_SPACES="4 2" # long comment', conf) + + # Check remote ssh location + b.click("#kdump-change-target") + b.wait_visible("#kdump-settings-dialog") + b.set_val("#kdump-settings-location", "ssh") + b.set_input_text("#kdump-settings-ssh-server", "admin@localhost") + b.set_input_text("#kdump-settings-ssh-key", "/home/admin/.ssh/id_rsa") + b.set_input_text("#kdump-settings-ssh-directory", "/var/tmp/crash") + b.click("button:contains('Save')") + b.wait_not_present("#kdump-settings-dialog") + b.wait_text("#kdump-change-target", "Remote over SSH") + conf = m.execute("cat /etc/sysconfig/kdump") + self.assertIn('KDUMP_SAVEDIR=ssh://admin@localhost/var/tmp/crash', conf) + self.assertIn('KDUMP_SSH_IDENTITY="/home/admin/.ssh/id_rsa"', conf) + + # Check remote NFS location + b.click("#kdump-change-target") + b.wait_visible("#kdump-settings-dialog") + b.set_val("#kdump-settings-location", "nfs") + b.set_input_text("#kdump-settings-nfs-server", "someserver") + b.set_input_text("#kdump-settings-nfs-export", "/srv") + b.click("button:contains('Save')") + b.wait_not_present("#kdump-settings-dialog") + b.wait_text("#kdump-change-target", "Remote over NFS") + conf = m.execute("cat /etc/sysconfig/kdump") + self.assertIn('KDUMP_SAVEDIR=nfs://someserver/srv', conf) + self.assertNotIn("ssh://", conf) + + # NFS with custom path + b.click("#kdump-change-target") + b.wait_visible("#kdump-settings-dialog") + b.set_input_text("#kdump-settings-nfs-directory", "dumps") + b.click("button:contains('Save')") + b.wait_not_present("#kdump-settings-dialog") + b.wait_text("#kdump-change-target", "Remote over NFS") + conf = m.execute("cat /etc/sysconfig/kdump") + self.assertIn('KDUMP_SAVEDIR=nfs://someserver/srv/dumps', conf) + + # Check local location + b.click("#kdump-change-target") + b.wait_visible("#kdump-settings-dialog") + b.set_val("#kdump-settings-location", "local") + b.set_input_text("#kdump-settings-local-directory", "/var/tmp") + b.click("button:contains('Save')") + b.wait_not_present("#kdump-settings-dialog") + b.wait_text("#kdump-change-target", "locally in /var/tmp") + conf = m.execute("cat /etc/sysconfig/kdump") + self.assertIn('KDUMP_SAVEDIR=file:///var/tmp', conf) + self.assertNotIn("nfs://", conf) + + # Check compression + conf = m.execute("cat /etc/sysconfig/kdump") + self.assertIn('KDUMP_DUMPFORMAT=compressed', conf) + b.click("#kdump-change-target") + b.wait_visible("#kdump-settings-dialog") + b.set_checked("#kdump-settings-compression", False) + b.click("button:contains('Save')") + b.wait_not_present("#kdump-settings-dialog") + conf = m.execute("cat /etc/sysconfig/kdump") + self.assertIn('KDUMP_DUMPFORMAT=ELF', conf) + b.click("#kdump-change-target") + b.wait_visible("#kdump-settings-dialog") + b.set_checked("#kdump-settings-compression", True) + b.click("button:contains('Save')") + b.wait_not_present("#kdump-settings-dialog") + conf = m.execute("cat /etc/sysconfig/kdump") + self.assertIn('KDUMP_DUMPFORMAT=compressed', conf) + + # Check remote FTP location (no config dialog) + m.execute("sed -i 's/KDUMP_SAVEDIR=.*/KDUMP_SAVEDIR=ftp:\\/\\/user@ftpserver\\/dumps1/g' /etc/sysconfig/kdump") + b.wait_text("#kdump-target-info", "Remote over FTP") + + # Check remote SFTP location (no config dialog) + m.execute("sed -i 's/KDUMP_SAVEDIR=.*/KDUMP_SAVEDIR=sftp:\\/\\/sftpserver\\/dumps2/g' /etc/sysconfig/kdump") + b.wait_text("#kdump-target-info", "Remote over SFTP") + + # Check remote CIFS location (no config dialog) + m.execute("sed -i 's/KDUMP_SAVEDIR=.*/KDUMP_SAVEDIR=cifs:\\/\\/user:pass@smbserver\\/dumps3/g' /etc/sysconfig/kdump") + b.wait_text("#kdump-target-info", "Remote over CIFS/SMB") + @skipImage("kexec-tools not installed", "fedora-coreos", "debian-stable", "debian-testing", "ubuntu-2204", "ubuntu-stable", "arch")
