Skip to content

Commit

Permalink
create: Show all operating systems
Browse files Browse the repository at this point in the history
This will show all operating systems, regardless of EOL or release
dates, but the recommended ones will be at the top.  Operating systems
with an expired EOL date will be annotated accordingly in the list.

The tests have been brought up-to-date with regard to what OSes are
actually in the list and are downloadable.

Fixes cockpit-project#509
  • Loading branch information
mvollmer committed Oct 24, 2024
1 parent 958c8e5 commit 0fae78e
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 35 deletions.
36 changes: 30 additions & 6 deletions src/components/create-vm-dialog/createVmDialog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ import {
correctSpecialCases,
filterReleaseEolDates,
getOSStringRepresentation,
getOSDescription,
needsRHToken,
isDownloadableOs,
loadOfflineToken,
Expand Down Expand Up @@ -405,10 +406,8 @@ const SourceRow = ({ connectionName, source, sourceType, networks, nodeDevices,
class OSRow extends React.Component {
constructor(props) {
super(props);
const IGNORE_VENDORS = ['ALTLinux', 'Mandriva', 'GNOME Project'];
const osInfoListExt = this.props.osInfoList
.map(os => correctSpecialCases(os))
.filter(os => filterReleaseEolDates(os) && !IGNORE_VENDORS.find(vendor => vendor == os.vendor))
.sort((a, b) => {
if (a.vendor == b.vendor) {
// Sort OS with numbered version by version
Expand All @@ -426,9 +425,20 @@ class OSRow extends React.Component {
return getOSStringRepresentation(a).toLowerCase() > getOSStringRepresentation(b).toLowerCase() ? 1 : -1;
});

const IGNORE_VENDORS = ['ALTLinux', 'Mandriva', 'GNOME Project'];
const newOsEntries = [];
const oldOsEntries = [];
for (const os of osInfoListExt) {
if (filterReleaseEolDates(os) && !IGNORE_VENDORS.find(vendor => vendor == os.vendor))
newOsEntries.push(os);
else
oldOsEntries.push(os);
}

this.state = {
typeAheadKey: Math.random(),
osEntries: osInfoListExt,
newOsEntries,
oldOsEntries,
};
this.createValue = os => {
return ({
Expand Down Expand Up @@ -474,9 +484,23 @@ class OSRow extends React.Component {
}}
onToggle={(_event, isOpen) => this.setState({ isOpen })}
isOpen={this.state.isOpen}
menuAppendTo="parent">
{this.state.osEntries.map(os => (<SelectOption key={os.id}
value={this.createValue(os)} />))}
menuAppendTo="parent"
isGrouped
>
<SelectGroup label={_("Recommended operating systems")} key="new">
{this.state.newOsEntries
.map(os => (<SelectOption key={os.id}
description={getOSDescription(os)}
value={this.createValue(os)} />))
}
</SelectGroup>
<SelectGroup label={_("Unsupported and older operating systems")} key="old">
{this.state.oldOsEntries
.map(os => (<SelectOption key={os.id}
description={getOSDescription(os)}
value={this.createValue(os)} />))
}
</SelectGroup>
</PFSelect>
<FormHelper helperTextInvalid={validationStateOS == "error" && validationFailed.os} />
</FormGroup>
Expand Down
14 changes: 14 additions & 0 deletions src/components/create-vm-dialog/createVmDialogUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,19 @@
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
*/

import cockpit from 'cockpit';
import React from 'react';
import { ExclamationTriangleIcon } from "@patternfly/react-icons";

import {
getTodayYearShifted,
} from "../../helpers.js";

import * as python from "python.js";
import autoDetectOSScript from './autoDetectOS.py';

const _ = cockpit.gettext;

const ACCEPT_RELEASE_DATES_AFTER = getTodayYearShifted(-3);
const ACCEPT_EOL_DATES_AFTER = getTodayYearShifted(-1);
const RHSM_TOKEN = "rhsm-offline-token";
Expand Down Expand Up @@ -76,6 +82,14 @@ export function filterReleaseEolDates(os) {
);
}

export function getOSDescription(os) {
if (os.eolDate && compareDates(ACCEPT_EOL_DATES_AFTER, os.eolDate) < 0)
return <span><ExclamationTriangleIcon className="ct-icon-exclamation-triangle" /> {cockpit.format(_("Vendor support ended $0"), os.eolDate)}</span>;
if (!os.eolDate && os.releaseDate && compareDates(ACCEPT_RELEASE_DATES_AFTER, os.releaseDate) < 0)
return cockpit.format(_("Released $0"), os.releaseDate);
return null;
}

export function compareDates(a, b, emptyFirst = false) {
if (!a) {
if (!b) {
Expand Down
5 changes: 5 additions & 0 deletions src/machines.scss
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,8 @@
#storage-pool-delete-modal span.pf-v5-c-check__body {
margin-block-start: 0;
}

#os-select .pf-v5-c-select__menu-item.pf-m-description {
display: flex;
align-items: baseline;
}
59 changes: 31 additions & 28 deletions test/check-machines-create
Original file line number Diff line number Diff line change
Expand Up @@ -91,16 +91,16 @@ class TestMachinesCreate(machineslib.VirtualMachinesCase):
pixel_test_tag="auto"))

# check if older os are filtered
runner.checkFilteredOsTest(TestMachinesCreate.VmDialog(self, os_name=config.REDHAT_RHEL_4_7_FILTERED_OS,
pixel_test_tag="filter"))

runner.checkFilteredOsTest(TestMachinesCreate.VmDialog(self, os_name=config.MANDRIVA_2011_FILTERED_OS))
runner.checkFilteredOsTest(TestMachinesCreate.VmDialog(self, os_name=config.OLD_FILTERED_OS,
os_is_old=True))

runner.checkFilteredOsTest(TestMachinesCreate.VmDialog(self, os_name=config.MAGEIA_3_FILTERED_OS))
runner.checkFilteredOsTest(TestMachinesCreate.VmDialog(self, os_name=config.UNSUPPORTED_FILTERED_OS,
os_is_unsupported=True,
pixel_test_tag="filter-unsupported"))

# check that newer oses are present and searchable with substring match
runner.checkFilteredOsTest(TestMachinesCreate.VmDialog(self, os_name=config.WINDOWS_SERVER_10,
os_search_name=config.WINDOWS_SERVER_10_SHORT))
runner.checkFilteredOsTest(TestMachinesCreate.VmDialog(self, os_name=config.NOT_FOUND_FILTERED_OS,
os_is_not_found=True,
pixel_test_tag="filter"))

# check OS versions are sorted in alphabetical order
runner.checkSortedOsTest(TestMachinesCreate.VmDialog(self), [config.FEDORA_29, config.FEDORA_28])
Expand Down Expand Up @@ -935,7 +935,9 @@ vnc_password= "{vnc_passwd}"
TREE_URL = 'https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/28/Server/x86_64/os'

# LINUX can be filtered if 3 years old
REDHAT_RHEL_4_7_FILTERED_OS = 'Red Hat Enterprise Linux 4.9'
OLD_FILTERED_OS = 'Red Hat Enterprise Linux 8.3'
UNSUPPORTED_FILTERED_OS = 'Fedora 34'
NOT_FOUND_FILTERED_OS = 'Red Hat Enterprise Linux 4.9'

FEDORA_28 = 'Fedora 28'
FEDORA_28_SHORTID = 'fedora28'
Expand All @@ -950,13 +952,6 @@ vnc_password= "{vnc_passwd}"

CENTOS_7 = 'CentOS 7'

MANDRIVA_2011_FILTERED_OS = 'Mandriva Linux 2011'

MAGEIA_3_FILTERED_OS = 'Mageia 3'

WINDOWS_SERVER_10 = 'Microsoft Windows 10'
WINDOWS_SERVER_10_SHORT = 'win'

class VmDialog:
vmId = 0

Expand All @@ -969,6 +964,9 @@ vnc_password= "{vnc_passwd}"
os_name="Fedora 28",
os_search_name=None,
os_short_id="fedora28",
os_is_unsupported=False,
os_is_old=False,
os_is_not_found=False,
expected_os_name=None,
is_unattended=None,
profile=None,
Expand Down Expand Up @@ -1017,6 +1015,9 @@ vnc_password= "{vnc_passwd}"
self.os_name = os_name
self.os_search_name = os_search_name
self.os_short_id = os_short_id
self.os_is_unsupported = os_is_unsupported
self.os_is_old = os_is_old
self.os_is_not_found = os_is_not_found
self.expected_os_name = expected_os_name
self.is_unattended = is_unattended
self.profile = profile
Expand Down Expand Up @@ -1078,7 +1079,7 @@ vnc_password= "{vnc_passwd}"
# https://bugzilla.redhat.com/show_bug.cgi?id=1987120
b.select_from_dropdown("#source-type", "url")
fake_fedora = "Fedora 28" # 128 MiB minimum storage
suse = "SUSE CaaS Platform Unknown (unknown)" # 20 GiB minimum storage
suse = "SUSE CaaS Platform Unknown" # 20 GiB minimum storage
b.set_input_text("#os-select-group input", fake_fedora)
b.click(f"#os-select li button:contains('{fake_fedora}')")
b.wait_val("#storage-limit", "128")
Expand Down Expand Up @@ -1176,23 +1177,25 @@ vnc_password= "{vnc_passwd}"

return self

def checkOsFiltered(self, present=False):
def checkOsFiltered(self):
b = self.browser

b.focus("#os-select-group input")
# os_search_name is meant to be used to test substring much
# os_search_name is meant to be used to test substring match
b.input_text(self.os_search_name or self.os_name)

if not present:
try:
with b.wait_timeout(5):
b.wait_in_text("#os-select li button", "No results found")
return self
except AssertionError:
# os found which is not ok
self.fail(f"{self.os_name} was not filtered")
if not self.os_is_not_found:
# There should be exactly one entry
b.wait_in_text("#os-select li button", self.os_name)
# It might have a description
if self.os_is_unsupported:
b.wait_in_text("#os-select li button", "Vendor support ended")
elif self.os_is_old:
b.wait_in_text("#os-select li button", "Released ")
else:
b.wait_visible(f"#os-select li button:contains({self.os_search_name})")
b.wait_in_text("#os-select li button", "No results found")

return self

def checkRhelIsDownloadable(self):
b = self.browser
Expand Down

0 comments on commit 0fae78e

Please sign in to comment.