Adam Majer
7109a2d114
- Update kdump-suse.patch to match upstream. - Add kdump-close.patch required by patches below. - Add kdump-refactor.patch and kdump-suse.patch to support SUSE kdump config management in cockpit. OBS-URL: https://build.opensuse.org/request/show/1001225 OBS-URL: https://build.opensuse.org/package/show/systemsmanagement:cockpit/cockpit?expand=0&rev=105
492 lines
21 KiB
Diff
492 lines
21 KiB
Diff
From d95850239f81a65c90743f20a0bc0450cb61823a Mon Sep 17 00:00:00 2001
|
|
From: Jacek Tomasiak <jacek.tomasiak@gmail.com>
|
|
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")
|