diff --git a/java/code/src/com/redhat/rhn/frontend/strings/java/StringResource_en_US.xml b/java/code/src/com/redhat/rhn/frontend/strings/java/StringResource_en_US.xml index 30287f7bd23b..ec5279a5ca57 100644 --- a/java/code/src/com/redhat/rhn/frontend/strings/java/StringResource_en_US.xml +++ b/java/code/src/com/redhat/rhn/frontend/strings/java/StringResource_en_US.xml @@ -9332,11 +9332,17 @@ Alternatively, you will want to download <strong>Incremental Channel Conte Update information about installed software (packages and products) - Update the system, rebooting if required + Update the system Perform a standalone Salt update + + Perform a reboot + + + Perform a reboot, only if required + Sync Salt beacons to the target system diff --git a/java/code/src/com/redhat/rhn/frontend/xmlrpc/recurringaction/RecurringCustomStateHandler.java b/java/code/src/com/redhat/rhn/frontend/xmlrpc/recurringaction/RecurringCustomStateHandler.java index 0920421f18e5..a645b31dc9c9 100644 --- a/java/code/src/com/redhat/rhn/frontend/xmlrpc/recurringaction/RecurringCustomStateHandler.java +++ b/java/code/src/com/redhat/rhn/frontend/xmlrpc/recurringaction/RecurringCustomStateHandler.java @@ -85,6 +85,17 @@ public int create(User loggedInUser, Map actionProps) { List states = (List) actionProps.get("states"); Set stateConfig = new HashSet<>(); + if (states.contains("reboot") && states.contains("rebootifneeded")) { + throw new InvalidArgsException("'reboot' and 'rebootifneeded' cannot be used together."); + } + else if (states.contains("reboot")) { + stateConfig.add(stateConfigFactory.getRecurringState(loggedInUser, "reboot", states.size())); + states.remove("reboot"); + } + else if (states.contains("rebootifneeded")) { + stateConfig.add(stateConfigFactory.getRecurringState(loggedInUser, "rebootifneeded", states.size())); + states.remove("rebootifneeded"); + } for (int i = 0; i < states.size(); i++) { try { stateConfig.add(stateConfigFactory.getRecurringState(loggedInUser, states.get(i), i + 1L)); @@ -129,6 +140,17 @@ public int update(User loggedInUser, Map actionProps) { } Set stateConfig = new HashSet<>(); + if (states.contains("reboot") && states.contains("rebootifneeded")) { + throw new InvalidArgsException("'reboot' and 'rebootifneeded' cannot be used together."); + } + else if (states.contains("reboot")) { + stateConfig.add(stateConfigFactory.getRecurringState(loggedInUser, "reboot", states.size())); + states.remove("reboot"); + } + else if (states.contains("rebootifneeded")) { + stateConfig.add(stateConfigFactory.getRecurringState(loggedInUser, "rebootifneeded", states.size())); + states.remove("rebootifneeded"); + } for (int i = 0; i < states.size(); i++) { try { stateConfig.add(stateConfigFactory.getRecurringState(loggedInUser, states.get(i), i + 1L)); diff --git a/java/spacewalk-java.changes.parlt.split-uptodate b/java/spacewalk-java.changes.parlt.split-uptodate new file mode 100644 index 000000000000..8a34755cadbf --- /dev/null +++ b/java/spacewalk-java.changes.parlt.split-uptodate @@ -0,0 +1 @@ +- Remove reboot from uptodate state, introduce reboot and rebootifneeded states diff --git a/schema/spacewalk/common/data/suseInternalState.sql b/schema/spacewalk/common/data/suseInternalState.sql index 268207a59cee..3dd31aab4c8b 100644 --- a/schema/spacewalk/common/data/suseInternalState.sql +++ b/schema/spacewalk/common/data/suseInternalState.sql @@ -43,3 +43,9 @@ INSERT INTO suseInternalState (id, name, label) INSERT INTO suseInternalState (id, name, label) VALUES (12, 'update-salt', 'Update Salt'); + +INSERT INTO suseInternalState (id, name, label) + VALUES (13, 'reboot', 'Reboot system'); + +INSERT INTO suseInternalState (id, name, label) + VALUES (14, 'rebootifneeded', 'Reboot system if needed'); diff --git a/schema/spacewalk/susemanager-schema.changes.parlt.split-uptodate b/schema/spacewalk/susemanager-schema.changes.parlt.split-uptodate new file mode 100644 index 000000000000..8a34755cadbf --- /dev/null +++ b/schema/spacewalk/susemanager-schema.changes.parlt.split-uptodate @@ -0,0 +1 @@ +- Remove reboot from uptodate state, introduce reboot and rebootifneeded states diff --git a/schema/spacewalk/upgrade/susemanager-schema-5.0.7-to-susemanager-schema-5.0.8/100-split-updtodate-state.sql b/schema/spacewalk/upgrade/susemanager-schema-5.0.7-to-susemanager-schema-5.0.8/100-split-updtodate-state.sql new file mode 100644 index 000000000000..4bff60a2647a --- /dev/null +++ b/schema/spacewalk/upgrade/susemanager-schema-5.0.7-to-susemanager-schema-5.0.8/100-split-updtodate-state.sql @@ -0,0 +1,14 @@ +INSERT INTO suseInternalState (id, name, label) + SELECT 13, 'reboot', 'Reboot system' + WHERE NOT EXISTS ( + SELECT 1 FROM suseInternalState + WHERE id = 13 + ); + +INSERT INTO suseInternalState (id, name, label) + SELECT 14, 'rebootifneeded', 'Reboot system if needed' + WHERE NOT EXISTS ( + SELECT 1 FROM suseInternalState + WHERE id = 14 + ); + diff --git a/susemanager-utils/susemanager-sls/salt/reboot.sls b/susemanager-utils/susemanager-sls/salt/reboot.sls new file mode 100644 index 000000000000..269f68616b3d --- /dev/null +++ b/susemanager-utils/susemanager-sls/salt/reboot.sls @@ -0,0 +1,3 @@ +mgr_reboot: + cmd.run: + - name: shutdown -r +5 diff --git a/susemanager-utils/susemanager-sls/salt/rebootifneeded.sls b/susemanager-utils/susemanager-sls/salt/rebootifneeded.sls new file mode 100644 index 000000000000..dca67c7b399d --- /dev/null +++ b/susemanager-utils/susemanager-sls/salt/rebootifneeded.sls @@ -0,0 +1,18 @@ +{%- if salt['pillar.get']('mgr_reboot_if_needed', True) and salt['pillar.get']('custom_info:mgr_reboot_if_needed', 'true')|lower in ('true', '1', 'yes', 't') %} +mgr_reboot_if_needed: + cmd.run: + - name: shutdown -r +5 +{%- if grains['os_family'] == 'RedHat' and grains['osmajorrelease'] >= 8 %} + - onlyif: 'dnf -q needs-restarting -r; [ $? -eq 1 ]' +{%- elif grains['os_family'] == 'RedHat' and grains['osmajorrelease'] >= 7 %} + - onlyif: 'needs-restarting -r; [ $? -eq 1 ]' +{%- elif grains['os_family'] == 'Debian' %} + - onlyif: + - test -e /var/run/reboot-required +{%- elif grains['os_family'] == 'Suse' and grains['osmajorrelease'] <= 12 %} + - onlyif: + - test -e /boot/do_purge_kernels +{%- else %} + - onlyif: 'zypper ps -s; [ $? -eq 102 ] || [ {{ patch_need_reboot }} -eq 0 ]' +{%- endif %} +{%- endif %} diff --git a/susemanager-utils/susemanager-sls/salt/uptodate.sls b/susemanager-utils/susemanager-sls/salt/uptodate.sls index ec75cc0583c1..e4a4b19dbe3f 100644 --- a/susemanager-utils/susemanager-sls/salt/uptodate.sls +++ b/susemanager-utils/susemanager-sls/salt/uptodate.sls @@ -45,24 +45,3 @@ mgr_keep_system_up2date_pkgs: - require: - sls: channels - mgr_keep_system_up2date_updatestack - -{%- if salt['pillar.get']('mgr_reboot_if_needed', True) and salt['pillar.get']('custom_info:mgr_reboot_if_needed', 'true')|lower in ('true', '1', 'yes', 't') %} -mgr_reboot_if_needed: - cmd.run: - - name: shutdown -r +5 - - require: - - pkg: mgr_keep_system_up2date_pkgs -{%- if grains['os_family'] == 'RedHat' and grains['osmajorrelease'] >= 8 %} - - onlyif: 'dnf -q needs-restarting -r; [ $? -eq 1 ]' -{%- elif grains['os_family'] == 'RedHat' and grains['osmajorrelease'] >= 7 %} - - onlyif: 'needs-restarting -r; [ $? -eq 1 ]' -{%- elif grains['os_family'] == 'Debian' %} - - onlyif: - - test -e /var/run/reboot-required -{%- elif grains['os_family'] == 'Suse' and grains['osmajorrelease'] <= 12 %} - - onlyif: - - test -e /boot/do_purge_kernels -{%- else %} - - onlyif: 'zypper ps -s; [ $? -eq 102 ] || [ {{ patch_need_reboot }} -eq 0 ]' -{%- endif %} -{%- endif %} diff --git a/susemanager-utils/susemanager-sls/susemanager-sls.changes.parlt.split-uptodate b/susemanager-utils/susemanager-sls/susemanager-sls.changes.parlt.split-uptodate new file mode 100644 index 000000000000..a0ffee764432 --- /dev/null +++ b/susemanager-utils/susemanager-sls/susemanager-sls.changes.parlt.split-uptodate @@ -0,0 +1,2 @@ +- Remove reboot from uptodate state, introduce reboot and rebootifneeded states + diff --git a/web/html/src/components/states-picker.tsx b/web/html/src/components/states-picker.tsx index 042f6ee1e44b..7c17acc3f575 100644 --- a/web/html/src/components/states-picker.tsx +++ b/web/html/src/components/states-picker.tsx @@ -64,7 +64,7 @@ class StatesPickerState { changed = new Map(); showSaltState?: any | null = undefined; rank?: boolean = undefined; - messages: MessageType[] | any; + messages: MessageType[] = []; } class StatesPicker extends React.Component { @@ -103,12 +103,38 @@ class StatesPicker extends React.Component }; save = () => { + let messages: MessageType[] = []; const channels = this.state.assigned; if (this.props.type === "state" && !channels.length) { this.setMessages(MessagesUtils.error(t("State configuration must not be empty"))); this.setState({ changed: new Map() }); this.hideRanking(); return; + } else if ( + channels.filter((channel) => channel.name.includes("reboot") && channel.type === "internal_state").length > 0 + ) { + // Put reboot states last + let position = 1; + let counter = 0; + _sortBy(channels, "position").forEach((channel) => { + if (channel.name.includes("reboot") && channel.type === "internal_state") { + if (channel.position !== channels.length) { + channel.position = channels.length; + messages = messages.concat(MessagesUtils.info(t("Reboot state will be put last."))); + } + counter++; + } else { + channel.position = position++; + } + }); + if (counter > 1) { + this.setMessages( + MessagesUtils.error(t("'Reboot system' and 'Reboot system if needed' states cannot be used together.")) + ); + this.setState({ changed: new Map() }); + this.hideRanking(); + return; + } } const request = this.props.saveRequest(channels).then( (data, textStatus, jqXHR) => { @@ -123,6 +149,7 @@ class StatesPicker extends React.Component } }); + messages = messages.concat(MessagesUtils.info(t("State assignments have been saved."))); this.setState({ changed: new Map(), // clear changed // Update the channels with the new data @@ -136,7 +163,7 @@ class StatesPicker extends React.Component results: this.getSortedList(newSearchResults), }, }); - this.setMessages(MessagesUtils.info(t("State assignments have been saved."))); + this.setMessages(messages); this.hideRanking(); }, (jqXHR, textStatus, errorThrown) => { @@ -316,7 +343,7 @@ class StatesPicker extends React.Component }; clearMessages() { - this.setMessages(null); + this.setMessages([]); } getCurrentAssignment = () => { diff --git a/web/spacewalk-web.changes.parlt.split-uptodate b/web/spacewalk-web.changes.parlt.split-uptodate new file mode 100644 index 000000000000..8a34755cadbf --- /dev/null +++ b/web/spacewalk-web.changes.parlt.split-uptodate @@ -0,0 +1 @@ +- Remove reboot from uptodate state, introduce reboot and rebootifneeded states