Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions libs/locales/lib/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"ai:1-{{count}} characters_plural": "1-{{count}} characters",
"ai:1-253 characters": "1-253 characters",
"ai:1-63 characters": "1-63 characters",
"ai:2 (Two-Nodes Arbiter)": "2 (Two-Nodes Arbiter)",
"ai:2-{{count}} characters": "2-{{count}} characters",
"ai:2-{{count}} characters_plural": "2-{{count}} characters",
"ai:3 (highly available cluster)": "3 (highly available cluster)",
Expand Down Expand Up @@ -815,7 +816,6 @@
"ai:The storage sizes will be used to store different files and data for cluster creation.": "The storage sizes will be used to store different files and data for cluster creation.",
"ai:The subnet prefix length to assign to each individual node. For example, if Cluster Network Host Prefix is set to 116, then each node is assigned a /116 subnet out of the given cidr (clusterNetworkCIDR), which allows for 4,094 (2^(128 - 116) - 2) pod IPs addresses. If you are required to provide access to nodes from an external network, configure load balancers and routers to manage the traffic.": "The subnet prefix length to assign to each individual node. For example, if Cluster Network Host Prefix is set to 116, then each node is assigned a /116 subnet out of the given cidr (clusterNetworkCIDR), which allows for 4,094 (2^(128 - 116) - 2) pod IPs addresses. If you are required to provide access to nodes from an external network, configure load balancers and routers to manage the traffic.",
"ai:The subnet prefix length to assign to each individual node. For example, if Cluster Network Host Prefix is set to 23, then each node is assigned a /23 subnet out of the given cidr (clusterNetworkCIDR), which allows for 510 (2^(32 - 23) - 2) pod IPs addresses. If you are required to provide access to nodes from an external network, configure load balancers and routers to manage the traffic.": "The subnet prefix length to assign to each individual node. For example, if Cluster Network Host Prefix is set to 23, then each node is assigned a /23 subnet out of the given cidr (clusterNetworkCIDR), which allows for 510 (2^(32 - 23) - 2) pod IPs addresses. If you are required to provide access to nodes from an external network, configure load balancers and routers to manage the traffic.",
"ai:The use of Tang encryption mode to encrypt your disks is only supported for bare metal or vSphere installations on user-provisioned infrastructure.": "The use of Tang encryption mode to encrypt your disks is only supported for bare metal or vSphere installations on user-provisioned infrastructure.",
"ai:The Value is not valid BMC address, supported protocols are redfish-virtualmedia or idrac-virtualmedia.": "The Value is not valid BMC address, supported protocols are redfish-virtualmedia or idrac-virtualmedia.",
"ai:The YAML file might not be formatted correctly. Use the template to format and try again.": "The YAML file might not be formatted correctly. Use the template to format and try again.",
"ai:There are no events that match the current filters. Adjust or clear the filters to view events.": "There are no events that match the current filters. Adjust or clear the filters to view events.",
Expand Down Expand Up @@ -859,7 +859,6 @@
"ai:To enable the host's baseboard management controller (BMC) on the hub cluster, you must first <2>create a provisioning configuration.</2>": "To enable the host's baseboard management controller (BMC) on the hub cluster, you must first <2>create a provisioning configuration.</2>",
"ai:To finish adding nodes to the cluster, approve the join request inside OpenShift Console's Nodes section.": "To finish adding nodes to the cluster, approve the join request inside OpenShift Console's Nodes section.",
"ai:To use static network configuration, follow the steps listed in the documentation.": "To use static network configuration, follow the steps listed in the documentation.",
"ai:To use this encryption method, enable TPMv2 encryption in the BIOS of each selected host.": "To use this encryption method, enable TPMv2 encryption in the BIOS of each selected host.",
"ai:To verify that the agent ran successfully, check the logs:": "To verify that the agent ran successfully, check the logs:",
"ai:To view detailed agent logs and communication use following command:": "To view detailed agent logs and communication use following command:",
"ai:Total compute": "Total compute",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import * as React from 'react';
import { Alert, AlertVariant, FlexItem, Form } from '@patternfly/react-core';
import { Form } from '@patternfly/react-core';
import { useFormikContext } from 'formik';

import { OpenShiftVersionDropdown, OpenShiftVersionModal } from '../../../common';
import {
isMajorMinorVersionEqualOrGreater,
OpenShiftVersionDropdown,
OpenShiftVersionModal,
} from '../../../common';
import { StaticTextField } from '../../../common/components/ui/StaticTextField';
import { PullSecret } from '../../../common/components/clusters';
import { OpenshiftVersionOptionType, SupportedCpuArchitecture } from '../../../common/types';
Expand Down Expand Up @@ -100,8 +104,13 @@ export const ClusterDetailsFormFields: React.FC<ClusterDetailsFormFieldsProps> =
return [];
}, [selectOptions, values.customOpenshiftSelect]);

const isDiskEncryptionEnabled =
values.enableDiskEncryptionOnMasters || values.enableDiskEncryptionOnWorkers;
const allowTNA = React.useMemo(() => {
const current =
values.customOpenshiftSelect?.version ||
versions.find((version) => version.value === values.openshiftVersion)?.version;

return isMajorMinorVersionEqualOrGreater(current, '4.19') && values.platform === 'baremetal';
}, [values.customOpenshiftSelect?.version, values.openshiftVersion, values.platform, versions]);

return (
<Form id="wizard-cluster-details__form">
Expand Down Expand Up @@ -163,44 +172,17 @@ export const ClusterDetailsFormFields: React.FC<ClusterDetailsFormFieldsProps> =
<ControlPlaneNodesDropdown
isDisabled={isEditFlow}
allowHighlyAvailable={allowHighlyAvailable}
allowTNA={allowTNA}
/>
{!isNutanix && (
<CpuArchitectureDropdown cpuArchitectures={cpuArchitectures} isDisabled={isEditFlow} />
)}

{extensionAfter?.['openshiftVersion'] && extensionAfter['openshiftVersion']}

{!isEditFlow && <PullSecret />}

{extensionAfter?.['pullSecret'] && extensionAfter['pullSecret']}
{/* <DiskEncryptionControlGroup
values={values}
isDisabled={isPullSecretSet}
isSNO={isSNO({ controlPlaneCount })}
/> */}
{isDiskEncryptionEnabled && values.diskEncryptionMode === 'tpmv2' && (
<Alert
variant={AlertVariant.warning}
isInline
title={
<FlexItem>
{t(
'ai:To use this encryption method, enable TPMv2 encryption in the BIOS of each selected host.',
)}
</FlexItem>
}
/>
)}
{isDiskEncryptionEnabled && values.diskEncryptionMode === 'tang' && (
<Alert
variant={AlertVariant.warning}
isInline
title={
<FlexItem>
{t(
'ai:The use of Tang encryption mode to encrypt your disks is only supported for bare metal or vSphere installations on user-provisioned infrastructure.',
)}
</FlexItem>
}
/>
)}
</Form>
);
};
1 change: 1 addition & 0 deletions libs/ui-lib/lib/cim/types/k8s/agent-cluster-install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export type AgentClusterInstallK8sResource = K8sResourceCommon & {
provisionRequirements: {
controlPlaneAgents: number;
workerAgents?: number;
arbiterAgents?: number;
};
networking: {
clusterNetwork?: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,21 @@ import { useTranslation } from '../../hooks/use-translation-wrapper';
import { getFieldId, StaticField } from '../..';
import { useField } from 'formik';
import toNumber from 'lodash-es/toNumber';
import OcmTNADisclaimer from './OcmTNADisclaimer';

const isItemEnabled = (value: number, allowHighlyAvailable?: boolean, allowTNA?: boolean) => {
switch (value) {
case 1:
case 3:
return true;
case 2:
return !!allowTNA;
case 4:
case 5:
return !!allowHighlyAvailable;
}
return false;
};

interface ControlPlaneNodesOption {
value: number;
Expand All @@ -21,9 +36,11 @@ interface ControlPlaneNodesOption {
const ControlPlaneNodesDropdown = ({
isDisabled = false,
allowHighlyAvailable,
allowTNA,
}: {
isDisabled?: boolean;
allowHighlyAvailable?: boolean;
allowTNA?: boolean;
}) => {
const { t } = useTranslation();
const [{ name, value: selectedValue }, , { setValue }] = useField<number>('controlPlaneCount');
Expand All @@ -32,6 +49,7 @@ const ControlPlaneNodesDropdown = ({

const options: ControlPlaneNodesOption[] = [
{ value: 1, label: t('ai:1 (Single Node OpenShift - not highly available cluster)') },
{ value: 2, label: t('ai:2 (Two-Nodes Arbiter)') },
{ value: 3, label: t('ai:3 (highly available cluster)') },
{ value: 4, label: t('ai:4 (highly available cluster+)') },
{ value: 5, label: t('ai:5 (highly available cluster++)') },
Expand All @@ -44,7 +62,8 @@ const ControlPlaneNodesDropdown = ({
}, [allowHighlyAvailable, selectedValue, setValue]);

const dropdownItems = options.map(({ value, label }) => {
const isItemEnabled = [1, 3].includes(value) || allowHighlyAvailable;
const isEnabled = isItemEnabled(value, allowHighlyAvailable, allowTNA);

const disabledReason = t('ai:This option is not available with the selected OpenShift version');
return (
<DropdownItem
Expand All @@ -55,7 +74,7 @@ const ControlPlaneNodesDropdown = ({
selected={selectedValue === value}
value={value}
>
<Tooltip hidden={isItemEnabled} content={disabledReason} position="top">
<Tooltip hidden={isEnabled} content={disabledReason} position="top">
<div>{label}</div>
</Tooltip>
</DropdownItem>
Expand All @@ -70,36 +89,47 @@ const ControlPlaneNodesDropdown = ({
setControlPlanelOpen(false);
};

return !isDisabled ? (
<FormGroup isInline fieldId={fieldId} label={t('ai:Number of control plane nodes')} isRequired>
<Dropdown
isOpen={controlPlanelOpen}
onSelect={onControlPlaneSelect}
onOpenChange={() => setControlPlanelOpen(!controlPlanelOpen)}
toggle={(toggleRef: React.Ref<MenuToggleElement>) => (
<MenuToggle
className="pf-v6-u-w-100"
ref={toggleRef}
isFullWidth
onClick={() => setControlPlanelOpen(!controlPlanelOpen)}
isExpanded={controlPlanelOpen}
return (
<>
{!isDisabled ? (
<FormGroup
isInline
fieldId={fieldId}
label={t('ai:Number of control plane nodes')}
isRequired
>
<Dropdown
isOpen={controlPlanelOpen}
onSelect={onControlPlaneSelect}
onOpenChange={() => setControlPlanelOpen(!controlPlanelOpen)}
toggle={(toggleRef: React.Ref<MenuToggleElement>) => (
<MenuToggle
className="pf-v5-u-w-100"
ref={toggleRef}
isFullWidth
onClick={() => setControlPlanelOpen(!controlPlanelOpen)}
isExpanded={controlPlanelOpen}
>
{selectedValue ? selectedValue : '3'}
</MenuToggle>
)}
shouldFocusToggleOnSelect
>
{selectedValue ? selectedValue : '3'}
</MenuToggle>
)}
shouldFocusToggleOnSelect
>
<DropdownList>{dropdownItems}</DropdownList>
</Dropdown>
</FormGroup>
) : (
<StaticField
name={'controlPlaneCount'}
label={t('ai:Number of control plane nodes')}
isRequired
>
{selectedValue}
</StaticField>
<DropdownList>{dropdownItems}</DropdownList>
</Dropdown>
</FormGroup>
) : (
<StaticField
name={'controlPlaneCount'}
label={t('ai:Number of control plane nodes')}
isRequired
>
{selectedValue}
</StaticField>
)}

{selectedValue === 2 && <OcmTNADisclaimer />}
</>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { Alert, AlertVariant, List, ListItem } from '@patternfly/react-core';
import { useTranslation } from '../../../common/hooks/use-translation-wrapper';
import { useTranslation } from '../../hooks/use-translation-wrapper';

const OcmTNADisclaimer = () => {
const { t } = useTranslation();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export const getClusterDetailsInitialValues = ({
diskEncryptionTangServers: parseTangServers(cluster?.diskEncryption?.tangServers),
diskEncryption: cluster?.diskEncryption ?? {},
cpuArchitecture: cluster?.cpuArchitecture || getDefaultCpuArchitecture(),
platform: cluster?.platform?.type || 'none',
platform: cluster?.platform?.type || 'baremetal',
customOpenshiftSelect: null,
userManagedNetworking: cluster?.userManagedNetworking || false,
enableDiskEncryptionOnArbiters: ['all', 'arbiters'].includes(
Expand Down
16 changes: 5 additions & 11 deletions libs/ui-lib/lib/common/config/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@ import {
ClusterValidationId,
DiskRole,
Event,
HostRoleUpdateParams,
HostValidationId,
} from '@openshift-assisted/types/assisted-installer-service';
import { ValidationGroup as ClusterValidationGroup } from '../types/clusters';
import buildManifest from '@openshift-assisted/ui-lib/package.json';
import { isInOcm } from '../api/axiosClient';

export const DEFAULT_POLLING_INTERVAL = 10 * 1000;
export const REDUCED_POLLING_INTERVAL = 10 * 1000 * 6;
Expand All @@ -35,15 +33,11 @@ export const hostRoles = (t: TFunction): HostRole[] => [
'ai:Runs application workloads. Connect at least 5 hosts to enable dedicated workers.',
),
},
...(isInOcm
? [
{
value: 'arbiter' as HostRoleUpdateParams,
label: t('ai:Arbiter'),
description: t('ai:Prevents split-brain scenarios and maintains quorum.'),
},
]
: []),
{
value: 'arbiter',
label: t('ai:Arbiter'),
description: t('ai:Prevents split-brain scenarios and maintains quorum.'),
},
];

export const clusterStatusLabels = (t: TFunction): { [key in Cluster['status']]: string } => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
useNewFeatureSupportLevel,
} from '../../../common/components/newFeatureSupportLevels';
import { isFeatureSupportedAndAvailable } from '../featureSupportLevels/featureStateUtils';
import OcmTNADisclaimer from './OcmTNADisclaimer';
import OcmTNADisclaimer from '../../../common/components/clusterConfiguration/OcmTNADisclaimer';
import OcmSNODisclaimer from './OcmSNODisclaimer';

const INPUT_NAME = 'controlPlaneCount';
Expand Down
Loading