diff --git a/libs/locales/lib/en/translation.json b/libs/locales/lib/en/translation.json
index 7fe3cd1886..e10494deb4 100644
--- a/libs/locales/lib/en/translation.json
+++ b/libs/locales/lib/en/translation.json
@@ -158,6 +158,9 @@
"ai:Check the proxy settings and verify that the assisted installer service is connected to a network. You can use nmcli to get additional information about your network configuration.": "Check the proxy settings and verify that the assisted installer service is connected to a network. You can use nmcli to get additional information about your network configuration.",
"ai:Check your VM reboot configuration": "Check your VM reboot configuration.",
"ai:Choose a namespace from your existing host inventory in order to select hosts for your node pools. The namespace will be composed of 1 or more infrastructure environments. After the cluster is created, a host will become a worker node.": "Select a namespace from your existing host inventory in order to select hosts for your node pools. The namespace will contain 1 or more infrastructure environments. After the cluster is created, a host becomes a worker node.",
+ "ai:Cisco Intersight URL": "Cisco Intersight URL",
+ "ai:Cisco Intersight URL is required": "Cisco Intersight URL is required",
+ "ai:Cisco Intersight URL must be a valid URL starting with \"http://\" or \"https://\"": "Cisco Intersight URL must be a valid URL starting with \"http://\" or \"https://\"",
"ai:Clear": "Clear",
"ai:Clear all filters": "Clear all filters",
"ai:Clear filters": "Clear filters",
@@ -204,8 +207,10 @@
"ai:Configuration is hanging for a long time.": "Configuration is hanging for a long time.",
"ai:Configuration may take a few minutes.": "Configuration might take a few minutes.",
"ai:Configure": "Configure",
+ "ai:Configure a custom URL to add hosts from Cisco Intersight on disconnected environments.": "Configure a custom URL to add hosts from Cisco Intersight on disconnected environments.",
"ai:Configure advanced networking properties (e.g. CIDR ranges).": "Configure advanced networking properties (for example, CIDR ranges).",
"ai:Configure cluster-wide trusted certificates": "Configure cluster-wide trusted certificates",
+ "ai:Configure custom URL for Cisco Intersight": "Configure custom URL for Cisco Intersight",
"ai:Configure environment": "Configure environment",
"ai:Configure host inventory settings": "Configure host inventory settings",
"ai:Configure load balancer on Amazon Web Services for me.": "Configure load balancer on Amazon Web Services for me.",
@@ -353,7 +358,6 @@
"ai:Failed to save configuration": "Failed to save configuration",
"ai:Failed to save host selection.": "Failed to save host selection.",
"ai:Failed to update host": "Failed to update host",
- "ai:Failed to update the AgentServiceConfig": "Failed to update the AgentServiceConfig",
"ai:Failed validations:": "Failed validations:",
"ai:Failing infrastructure environment": "Failing infrastructure environment",
"ai:Fence Agents Remediation requirements": "Fence Agents Remediation requirements",
@@ -696,6 +700,7 @@
"ai:Provide an endpoint for users, both human and machine, to interact with and configure the platform. If needed, contact your IT manager for more information. {{vipHelperSuffix}}": "Provide an endpoint for users, both human and machine, to interact with and configure the platform. If needed, contact your IT manager for more information. {{vipHelperSuffix}}",
"ai:Provide an SSH key to be able to connect to the hosts for debugging purposes during the discovery process": "Provide an SSH key to be able to connect to the hosts for debugging purposes during the discovery process",
"ai:Provide as many labels as you can to narrow the list to relevant hosts only.": "Provide as many labels as you can to narrow the list to relevant hosts.",
+ "ai:Provide the complete URL, including the protocol and parameters.": "Provide the complete URL, including the protocol and parameters.",
"ai:Provided cluster configuration is not valid": "Provided cluster configuration is not valid",
"ai:Provisioned": "Provisioned",
"ai:Provisioning": "Provisioning",
diff --git a/libs/ui-lib/lib/cim/components/modals/AddHostModal.tsx b/libs/ui-lib/lib/cim/components/modals/AddHostModal.tsx
index 007b6dbf08..f5233b8a12 100644
--- a/libs/ui-lib/lib/cim/components/modals/AddHostModal.tsx
+++ b/libs/ui-lib/lib/cim/components/modals/AddHostModal.tsx
@@ -15,6 +15,7 @@ import { useTranslation } from '../../../common/hooks/use-translation-wrapper';
import { EnvironmentErrors } from '../InfraEnv/EnvironmentErrors';
import { InfraEnvK8sResource } from '../../types';
import DownloadIpxeScript from '../../../common/components/clusterConfiguration/DownloadIpxeScript';
+import { useAgentServiceConfig } from '../../hooks';
type AddHostModalStepType = 'config' | 'download';
@@ -27,12 +28,24 @@ const AddHostModal: React.FC = ({
docVersion,
isIPXE,
}) => {
+ const { t } = useTranslation();
const hasDHCP = infraEnv.metadata?.labels?.networkType !== 'static';
const sshPublicKey = infraEnv.spec?.sshAuthorizedKey || agentClusterInstall?.spec?.sshPublicKey;
const { httpProxy, httpsProxy, noProxy } = infraEnv.spec?.proxy || {};
const imageType = infraEnv.spec?.imageType || 'minimal-iso';
const [dialogType, setDialogType] = React.useState('config');
- const { t } = useTranslation();
+
+ const [ciscoUrl, setCiscoUrl] = React.useState();
+ const [agentServiceConfig, loaded, error] = useAgentServiceConfig({ name: 'agent' });
+
+ React.useEffect(() => {
+ if (loaded && !error) {
+ if (agentServiceConfig && agentServiceConfig.metadata?.annotations?.['ciscoIntersightURL']) {
+ setCiscoUrl(agentServiceConfig.metadata?.annotations?.['ciscoIntersightURL']);
+ }
+ }
+ }, [agentServiceConfig, error, loaded]);
+
const handleIsoConfigSubmit = async (
values: DiscoveryImageFormValues,
formikActions: FormikHelpers,
@@ -92,6 +105,7 @@ const AddHostModal: React.FC = ({
onReset={agentClusterInstall ? () => setDialogType('config') : undefined}
hasDHCP={hasDHCP}
docVersion={docVersion}
+ ciscoUrl={ciscoUrl}
/>
)}
>
@@ -107,12 +121,14 @@ const GeneratingIsoDownload = ({
onReset,
hasDHCP,
docVersion,
+ ciscoUrl,
}: {
infraEnv: InfraEnvK8sResource;
onClose: VoidFunction;
onReset?: VoidFunction;
hasDHCP: boolean;
docVersion: string;
+ ciscoUrl?: string;
}) => {
const { t } = useTranslation();
return infraEnv.status?.isoDownloadURL ? (
@@ -122,6 +138,7 @@ const GeneratingIsoDownload = ({
onReset={onReset}
hasDHCP={hasDHCP}
docVersion={docVersion}
+ ciscoUrl={ciscoUrl}
/>
) : (
diff --git a/libs/ui-lib/lib/cim/components/modals/CimConfiguration/CimConfigurationForm.css b/libs/ui-lib/lib/cim/components/modals/CimConfiguration/CimConfigurationForm.css
deleted file mode 100644
index cc4c9997cc..0000000000
--- a/libs/ui-lib/lib/cim/components/modals/CimConfiguration/CimConfigurationForm.css
+++ /dev/null
@@ -1,23 +0,0 @@
-.cim-config-form-title .pf-v5-c-form__label-text {
- font-size: larger;
-}
-
-.cim-config-form-volume {
- white-space: nowrap;
-}
-
-.cim-config-form-aws-label {
- white-space: nowrap;
-}
-
-.cim-config-form-aws {
- margin-bottom: var(--pf-v5-global--spacer--md);
-}
-
-.cim-config-form-volume input {
- width: 10rem;
-}
-
-.cim-config-modal .pf-v5-c-modal-box__body {
- overflow: hidden;
-}
diff --git a/libs/ui-lib/lib/cim/components/modals/CimConfiguration/CimConfigurationForm.tsx b/libs/ui-lib/lib/cim/components/modals/CimConfiguration/CimConfigurationForm.tsx
deleted file mode 100644
index 08b6d9b825..0000000000
--- a/libs/ui-lib/lib/cim/components/modals/CimConfiguration/CimConfigurationForm.tsx
+++ /dev/null
@@ -1,290 +0,0 @@
-import * as React from 'react';
-import { Trans } from 'react-i18next';
-import {
- Flex,
- FlexItem,
- Form,
- FormGroup,
- Popover,
- Checkbox,
- TextInput,
- FormHelperText,
- HelperText,
- HelperTextItem,
- Icon,
-} from '@patternfly/react-core';
-import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
-import { ExclamationCircleIcon } from '@patternfly/react-icons/dist/js/icons/exclamation-circle-icon';
-import { HelpIcon } from '@patternfly/react-icons/dist/js/icons/help-icon';
-
-import { useTranslation } from '../../../../common/hooks/use-translation-wrapper';
-import { CimConfigurationFormProps } from './types';
-
-import './CimConfigurationForm.css';
-
-export const CimConfigurationForm: React.FC = ({
- docConfigUrl,
- docConfigAwsUrl,
- isEdit,
- isInProgressPeriod,
- dbVolSize,
- dbVolSizeValidation,
- setDbVolSize,
- fsVolSize,
- fsVolSizeValidation,
- setFsVolSize,
- imgVolSize,
- imgVolSizeValidation,
- setImgVolSize,
- configureLoadBalancer,
- configureLoadBalancerInitial,
- setConfigureLoadBalancer,
-}) => {
- const { t } = useTranslation();
-
- const getNumber = (v: string, min: number): number => {
- const p = parseFloat(v);
- if (isNaN(p)) {
- // Do not check for minimum here - keep it on validation
- return min;
- }
- return p;
- };
-
- const awsHelp = (
-
-
- ai:Learn more about enabling CIM on AWS
-
-
- }
- >
-
-
- );
-
- return (
-
- );
-};
diff --git a/libs/ui-lib/lib/cim/components/modals/CimConfiguration/CimConfigurationFormFields.tsx b/libs/ui-lib/lib/cim/components/modals/CimConfiguration/CimConfigurationFormFields.tsx
new file mode 100644
index 0000000000..dce26cd5f0
--- /dev/null
+++ b/libs/ui-lib/lib/cim/components/modals/CimConfiguration/CimConfigurationFormFields.tsx
@@ -0,0 +1,258 @@
+import * as React from 'react';
+import { Trans } from 'react-i18next';
+import {
+ Flex,
+ FlexItem,
+ Form,
+ FormGroup,
+ Icon,
+ InputGroup,
+ InputGroupItem,
+ InputGroupText,
+ TextContent,
+ Text,
+ TextVariants,
+ Stack,
+ StackItem,
+} from '@patternfly/react-core';
+import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
+import { HelpIcon } from '@patternfly/react-icons/dist/js/icons/help-icon';
+
+import { useTranslation } from '../../../../common/hooks/use-translation-wrapper';
+import { CheckboxField, InputField, PopoverIcon } from '../../../../common';
+import { CimConfigurationFormFieldsProps, CimConfigurationValues } from './types';
+import { useFormikContext } from 'formik';
+import { isIngressController } from './persist';
+
+export const CimConfigurationFormFields = ({
+ platform,
+ docConfigUrl,
+ docConfigAwsUrl,
+ isEdit,
+ isInProgressPeriod,
+ configureLoadBalancerInitial,
+ setConfigureLoadBalancerInitial,
+}: CimConfigurationFormFieldsProps) => {
+ const { t } = useTranslation();
+
+ const { setFieldValue, values } = useFormikContext();
+
+ React.useEffect(
+ () => {
+ const doItAsync = async (): Promise => {
+ if (platform === 'AWS') {
+ if (!isEdit || (await isIngressController())) {
+ setFieldValue('configureLoadBalancer', true);
+ setConfigureLoadBalancerInitial(true);
+ return;
+ }
+ }
+
+ setFieldValue('configureLoadBalancer', false);
+ setConfigureLoadBalancerInitial(false);
+ };
+
+ void doItAsync();
+ },
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ [platform],
+ );
+
+ return (
+
+ );
+};
diff --git a/libs/ui-lib/lib/cim/components/modals/CimConfiguration/CimConfigurationModal.css b/libs/ui-lib/lib/cim/components/modals/CimConfiguration/CimConfigurationModal.css
deleted file mode 100644
index 809e49e935..0000000000
--- a/libs/ui-lib/lib/cim/components/modals/CimConfiguration/CimConfigurationModal.css
+++ /dev/null
@@ -1,3 +0,0 @@
-.cim-config-modal .pf-v5-c-alert {
- margin-bottom: var(--pf-v5-global--spacer--md);
-}
diff --git a/libs/ui-lib/lib/cim/components/modals/CimConfiguration/CimConfigurationModal.tsx b/libs/ui-lib/lib/cim/components/modals/CimConfiguration/CimConfigurationModal.tsx
index 3bb9303076..26872d95f0 100644
--- a/libs/ui-lib/lib/cim/components/modals/CimConfiguration/CimConfigurationModal.tsx
+++ b/libs/ui-lib/lib/cim/components/modals/CimConfiguration/CimConfigurationModal.tsx
@@ -1,4 +1,6 @@
import * as React from 'react';
+import { Formik, FormikHelpers } from 'formik';
+import * as Yup from 'yup';
import {
Alert,
AlertVariant,
@@ -6,21 +8,24 @@ import {
ButtonVariant,
Modal,
ModalVariant,
+ TextContent,
+ Text,
+ StackItem,
+ Stack,
} from '@patternfly/react-core';
+import parseUrl from 'parse-url';
import { useTranslation } from '../../../../common/hooks/use-translation-wrapper';
import { getStorageSizeGiB } from '../../helpers';
import { AlertPayload } from '../../../../common';
-import { CimConfigurationModalProps, CimConfiguratioProps } from './types';
-import { CimConfigurationForm } from './CimConfigurationForm';
-import { isIngressController, onEnableCIM } from './persist';
+import { CimConfigurationModalProps, CimConfigurationValues } from './types';
+import { onEnableCIM } from './persist';
import { CimConfigDisconnectedAlert } from './CimConfigDisconnectedAlert';
import { MIN_DB_VOL_SIZE, MIN_FS_VOL_SIZE, MIN_IMG_VOL_SIZE } from './constants';
import { isCIMConfigProgressing } from './utils';
import { resetCimConfigProgressAlertSuccessStatus } from './CimConfigProgressAlert';
-
-import './CimConfigurationModal.css';
+import { CimConfigurationFormFields } from './CimConfigurationFormFields';
export const CimConfigurationModal: React.FC = ({
isOpen,
@@ -30,136 +35,41 @@ export const CimConfigurationModal: React.FC = ({
docDisconnectedUrl,
docConfigUrl,
docConfigAwsUrl,
-
- getResource,
- listResources,
- patchResource,
- createResource,
}) => {
const { t } = useTranslation();
const [error, setError] = React.useState();
- const [isSaving, setSaving] = React.useState(false);
-
- const [dbVolSize, _setDbVolSize] = React.useState(() =>
- getStorageSizeGiB(10, agentServiceConfig?.spec?.databaseStorage?.resources?.requests?.storage),
- );
- const [dbVolSizeValidation, setDbVolSizeValidation] = React.useState();
-
- const [fsVolSize, _setFsVolSize] = React.useState(() =>
- getStorageSizeGiB(
- 100,
- agentServiceConfig?.spec?.filesystemStorage?.resources?.requests?.storage,
- ),
- );
- const [fsVolSizeValidation, setFsVolSizeValidation] = React.useState();
- const [imgVolSize, _setImgVolSize] = React.useState(() =>
- getStorageSizeGiB(50, agentServiceConfig?.spec?.imageStorage?.resources?.requests?.storage),
- );
- const [imgVolSizeValidation, setImgVolSizeValidation] = React.useState();
-
- const [configureLoadBalancer, setConfigureLoadBalancer] = React.useState(
- platform === 'AWS',
- );
const [configureLoadBalancerInitial, setConfigureLoadBalancerInitial] = React.useState(true);
-
- const setDbVolSize = (v: number): void => {
- if (v < MIN_DB_VOL_SIZE) {
- setDbVolSizeValidation(t('ai:Minimal value is 1Gi'));
- } else {
- setDbVolSizeValidation(undefined);
- }
- _setDbVolSize(v);
- };
- const setFsVolSize = (v: number): void => {
- if (v < MIN_FS_VOL_SIZE) {
- setFsVolSizeValidation(t('ai:Minimal value is 1Gi'));
- } else {
- setFsVolSizeValidation(undefined);
- }
- _setFsVolSize(v);
- };
- const setImgVolSize = (v: number): void => {
- if (v < MIN_IMG_VOL_SIZE) {
- setImgVolSizeValidation(t('ai:Minimal value is 10Gi'));
- } else {
- setImgVolSizeValidation(undefined);
- }
- _setImgVolSize(v);
- };
-
const isEdit = !!agentServiceConfig;
- React.useEffect(
- () => {
- const doItAsync = async (): Promise => {
- if (platform === 'AWS') {
- if (!isEdit || (await isIngressController(getResource))) {
- setConfigureLoadBalancer(true);
- setConfigureLoadBalancerInitial(true);
- return;
- }
- }
-
- setConfigureLoadBalancer(false);
- setConfigureLoadBalancerInitial(false);
- };
-
- void doItAsync();
- },
- // eslint-disable-next-line react-hooks/exhaustive-deps
- [platform],
- );
-
- const formProps: CimConfiguratioProps = {
- dbVolSize,
- dbVolSizeValidation,
- setDbVolSize,
- fsVolSize,
- fsVolSizeValidation,
- setFsVolSize,
- imgVolSize,
- imgVolSizeValidation,
- setImgVolSize,
-
- configureLoadBalancer,
- configureLoadBalancerInitial,
- setConfigureLoadBalancer,
- };
-
- const onConfigure = () => {
- const doItAsync = async (): Promise => {
- setSaving(true);
- setError(undefined);
- resetCimConfigProgressAlertSuccessStatus();
-
- if (
- await onEnableCIM({
- t,
- setError,
- getResource,
- listResources,
- patchResource,
- createResource,
- agentServiceConfig,
-
- platform,
- dbVolSizeGiB: dbVolSize,
- fsVolSizeGiB: fsVolSize,
- imgVolSizeGiB: imgVolSize,
- configureLoadBalancer,
- })
- ) {
- // successfuly persisted
- onClose();
- }
-
+ const onConfigure = async (
+ values: CimConfigurationValues,
+ helpers: FormikHelpers,
+ ) => {
+ setError(undefined);
+ helpers.setSubmitting(true);
+ resetCimConfigProgressAlertSuccessStatus();
+
+ if (
+ await onEnableCIM({
+ t,
+ setError,
+ agentServiceConfig,
+ platform,
+ dbVolSizeGiB: values.dbVolSize,
+ fsVolSizeGiB: values.fsVolSize,
+ imgVolSizeGiB: values.imgVolSize,
+ configureLoadBalancer: values.configureLoadBalancer,
+ ciscoIntersightURL: values.addCiscoIntersightUrl ? values.ciscoIntersightURL : undefined,
+ })
+ ) {
+ // successfully persisted
+ onClose();
+ } else {
// keep modal open and show error
- setConfigureLoadBalancerInitial(configureLoadBalancer);
- setSaving(false);
- };
-
- void doItAsync();
+ setConfigureLoadBalancerInitial(values.configureLoadBalancer);
+ helpers.setSubmitting(false);
+ }
};
const isError = !!error?.title; // this is a communication error only (not the one from agentServiceConfig)
@@ -167,75 +77,140 @@ export const CimConfigurationModal: React.FC = ({
const isConfigure =
!isEdit || !configureLoadBalancerInitial; /* The only possible change for the Edit flow */
- const isConfigureDisabled = !!(
- isSaving ||
- dbVolSizeValidation ||
- fsVolSizeValidation ||
- imgVolSizeValidation ||
- (isEdit && configureLoadBalancerInitial === configureLoadBalancer)
- );
-
const isInProgressPeriod = isCIMConfigProgressing({ agentServiceConfig });
- // const isConfiguring = isSaving || isInProgressPeriod;
-
- let actions: React.ReactNode[];
- if (isConfigure) {
- actions = [
- ,
- ,
- ];
- } else {
- actions = [
- ,
- ];
- }
+
+ const initialValues: CimConfigurationValues = {
+ dbVolSize: getStorageSizeGiB(
+ 10,
+ agentServiceConfig?.spec?.databaseStorage?.resources?.requests?.storage,
+ ),
+ fsVolSize: getStorageSizeGiB(
+ 100,
+ agentServiceConfig?.spec?.filesystemStorage?.resources?.requests?.storage,
+ ),
+ imgVolSize: getStorageSizeGiB(
+ 50,
+ agentServiceConfig?.spec?.imageStorage?.resources?.requests?.storage,
+ ),
+ configureLoadBalancer: platform === 'AWS',
+ addCiscoIntersightUrl: !!agentServiceConfig?.metadata?.annotations?.['ciscoIntersightURL'],
+ ciscoIntersightURL: agentServiceConfig?.metadata?.annotations?.['ciscoIntersightURL'] || '',
+ };
+
+ const validationSchema = Yup.object({
+ dbVolSize: Yup.number().min(MIN_DB_VOL_SIZE, t('ai:Minimal value is 1Gi')).required(),
+ fsVolSize: Yup.number().min(MIN_FS_VOL_SIZE, t('ai:Minimal value is 1Gi')).required(),
+ imgVolSize: Yup.number().min(MIN_IMG_VOL_SIZE, t('ai:Minimal value is 10Gi')).required(),
+ configureLoadBalancer: Yup.boolean(),
+ ciscoIntersightURL: Yup.string().when('addCiscoIntersightUrl', {
+ is: true,
+ then: (schema) =>
+ schema
+ .required(t('ai:Cisco Intersight URL is required'))
+ .test(
+ 'url-valid',
+ t('ai:Cisco Intersight URL must be a valid URL starting with "http://" or "https://"'),
+ (val) => {
+ try {
+ const url = parseUrl(val);
+ return url.protocol === 'http' || url.protocol === 'https';
+ } catch (error) {
+ return false;
+ }
+ },
+ ),
+ }),
+ });
return (
-
- {t(
- 'ai:Configuring the host inventory settings will enable the Central Infrastructure Management.',
- )}
- {isError && (
-
- {error.message}
-
- )}
-
-
- {isConfigure && (
-
+ {({ values, handleSubmit, isValid, isSubmitting }) => (
+ void handleSubmit()}
+ >
+ {t('ai:Configure')}
+ ,
+ ,
+ ]
+ : [
+ ,
+ ]
+ }
+ variant={ModalVariant.medium}
+ id="cim-config-modal"
+ >
+
+
+
+
+ {t(
+ 'ai:Configuring the host inventory settings will enable the Central Infrastructure Management.',
+ )}
+
+
+
+
+ {isError && (
+
+
+ {error.message}
+
+
+ )}
+
+
+
+
+
+
+
+
+
+ {isConfigure && (
+
+
+
+ )}
+
+
)}
-
+
);
};
diff --git a/libs/ui-lib/lib/cim/components/modals/CimConfiguration/persist.ts b/libs/ui-lib/lib/cim/components/modals/CimConfiguration/persist.ts
index 53469175db..1841d6a536 100644
--- a/libs/ui-lib/lib/cim/components/modals/CimConfiguration/persist.ts
+++ b/libs/ui-lib/lib/cim/components/modals/CimConfiguration/persist.ts
@@ -1,17 +1,21 @@
-import { K8sResourceCommon } from '@openshift-console/dynamic-plugin-sdk';
+import {
+ k8sCreate,
+ k8sGet,
+ k8sListItems,
+ k8sPatch,
+ K8sResourceCommon,
+} from '@openshift-console/dynamic-plugin-sdk';
import { AlertVariant } from '@patternfly/react-core';
import { TFunction } from 'i18next';
import { getErrorMessage } from '../../../../common/utils';
import {
AgentServiceConfigK8sResource,
- convertOCPtoCIMResourceHeader,
- CreateResourceFuncType,
- GetResourceFuncType,
- ListResourcesFuncType,
- PatchResourceFuncType,
- ResourcePatch,
+ AgentServiceConfigModel,
+ IngressControllerModel,
+ ProvisioningModel,
RouteK8sResource,
+ RouteModel,
} from '../../../types';
import { LOCAL_STORAGE_ID_LAST_UPDATE_TIMESTAMP } from './utils';
@@ -32,14 +36,10 @@ const ASSISTED_IMAGE_SERVICE_ROUTE_PREFIX = 'assisted-image-service-multicluster
const getAssistedImageServiceRoute = async (
t: TFunction,
setError: SetErrorFuncType,
- listResources: ListResourcesFuncType,
): Promise => {
- let allRoutes;
+ let allRoutes: RouteK8sResource[] = [];
try {
- allRoutes = (await listResources({
- kind: 'Route',
- apiVersion: 'route.openshift.io/v1',
- })) as RouteK8sResource[];
+ allRoutes = await k8sListItems({ model: RouteModel, queryParams: {} });
} catch (e) {
// console.error('Failed to read all routes: ', allRoutes);
setError({
@@ -50,7 +50,7 @@ const getAssistedImageServiceRoute = async (
}
const assistedImageServiceRoute = allRoutes?.find(
- (r: RouteK8sResource) => r.metadata?.name === 'assisted-image-service',
+ (r) => r.metadata?.name === 'assisted-image-service',
);
if (!assistedImageServiceRoute?.spec?.host) {
@@ -92,7 +92,6 @@ const getClusterDomain = (
const patchAssistedImageServiceRoute = async (
t: TFunction,
setError: SetErrorFuncType,
- patchResource: PatchResourceFuncType,
assistedImageServiceRoute: RouteK8sResource,
domain: string,
@@ -102,7 +101,7 @@ const patchAssistedImageServiceRoute = async (
const labels = assistedImageServiceRoute.metadata?.labels || {};
labels['router-type'] = 'nlb';
- const patches: ResourcePatch[] = [
+ const patches = [
{
op: 'replace',
path: '/spec/host',
@@ -116,7 +115,11 @@ const patchAssistedImageServiceRoute = async (
];
try {
- await patchResource(convertOCPtoCIMResourceHeader(assistedImageServiceRoute), patches);
+ await k8sPatch({
+ model: RouteModel,
+ resource: assistedImageServiceRoute,
+ data: patches,
+ });
} catch (e) {
// console.error('Failed to patch assisted-image-service route: ', e, patches);
setError({
@@ -128,15 +131,12 @@ const patchAssistedImageServiceRoute = async (
return true;
};
-export const isIngressController = async (getResource: GetResourceFuncType): Promise => {
+export const isIngressController = async (): Promise => {
try {
- await getResource({
- apiVersion: 'operator.openshift.io/v1',
- kind: 'IngressController',
- metadata: {
- name: 'ingress-controller-with-nlb',
- namespace: 'openshift-ingress-operator',
- },
+ await k8sGet({
+ name: 'ingress-controller-with-nlb',
+ ns: 'openshift-ingress-operator',
+ model: IngressControllerModel,
});
return true;
@@ -148,7 +148,6 @@ export const isIngressController = async (getResource: GetResourceFuncType): Pro
const createIngressController = async (
t: TFunction,
setError: SetErrorFuncType,
- createResource: CreateResourceFuncType,
domain: string,
): Promise => {
@@ -184,7 +183,7 @@ const createIngressController = async (
};
try {
- await createResource(ingressController);
+ await k8sCreate({ model: IngressControllerModel, data: ingressController });
return true;
} catch (e) {
// console.error('Create IngressController error: ', e);
@@ -199,24 +198,19 @@ const createIngressController = async (
const patchProvisioningConfiguration = async ({
t,
setError,
- patchResource,
- getResource,
}: {
t: TFunction;
setError: SetErrorFuncType;
- patchResource: PatchResourceFuncType;
- getResource: GetResourceFuncType;
}) => {
try {
- const provisioning = (await getResource({
- kind: 'Provisioning',
- apiVersion: 'metal3.io/v1alpha1',
- metadata: {
- name: 'provisioning-configuration',
- },
- })) as K8sResourceCommon & { spec?: { watchAllNamespaces?: boolean } };
+ const provisioning = await k8sGet<
+ K8sResourceCommon & { spec?: { watchAllNamespaces?: boolean } }
+ >({
+ model: ProvisioningModel,
+ name: 'provisioning-configuration',
+ });
- const patches: ResourcePatch[] = [
+ const patches = [
{
op: provisioning.spec?.watchAllNamespaces ? 'replace' : 'add',
path: '/spec/watchAllNamespaces',
@@ -224,7 +218,11 @@ const patchProvisioningConfiguration = async ({
},
];
- await patchResource(convertOCPtoCIMResourceHeader(provisioning), patches);
+ await k8sPatch({
+ model: ProvisioningModel,
+ resource: provisioning,
+ data: patches,
+ });
} catch (e) {
// console.error('Failed to patch provisioning-configuration: ', e);
setError({
@@ -238,18 +236,18 @@ const patchProvisioningConfiguration = async ({
const createAgentServiceConfig = async ({
t,
setError,
- createResource,
dbVolSizeGiB,
fsVolSizeGiB,
imgVolSizeGiB,
+ ciscoIntersightURL,
}: {
t: TFunction;
setError: SetErrorFuncType;
- createResource: CreateResourceFuncType;
dbVolSizeGiB: number;
fsVolSizeGiB: number;
imgVolSizeGiB: number;
+ ciscoIntersightURL?: string;
}): Promise => {
try {
const agentServiceConfig = {
@@ -257,6 +255,7 @@ const createAgentServiceConfig = async ({
kind: 'AgentServiceConfig',
metadata: {
name: 'agent',
+ annotations: {},
},
spec: {
databaseStorage: {
@@ -286,79 +285,32 @@ const createAgentServiceConfig = async ({
},
};
- await createResource(agentServiceConfig);
- return true;
- } catch (e) {
- // console.error('Failed to create AgentServiceConfig: ', e);
- setError({
- title: t('ai:Failed to create AgentServiceConfig'),
- message: getErrorMessage(e),
- });
- return false;
- }
-};
+ if (ciscoIntersightURL) {
+ agentServiceConfig.metadata = {
+ ...agentServiceConfig.metadata,
+ annotations: { ciscoIntersightURL },
+ };
+ }
-/* Following functions are tested but recently not used.
-const patchAgentServiceConfig = async ({
- t,
- setError,
- patchResource,
- agentServiceConfig,
- imgVolSizeGB,
-}: {
- t: TFunction;
- setError: SetErrorFuncType;
- patchResource: PatchResourceFuncType;
- agentServiceConfig: AgentServiceConfigK8sResource;
+ await k8sCreate({
+ model: AgentServiceConfigModel,
+ data: agentServiceConfig,
+ });
- imgVolSizeGB: number;
-}): Promise => {
- try {
- const patches: ResourcePatch[] = [
- {
- op: 'replace',
- path: '/spec/imageStorage/resources/requests/storage',
- value: `${imgVolSizeGB}G`,
- },
- ];
- await patchResource(agentServiceConfig, patches);
return true;
} catch (e) {
- console.error('Failed to patch AgentServiceConfig: ', e);
setError({
- title: t('ai:Failed to update the AgentServiceConfig'),
+ title: t('ai:Failed to create AgentServiceConfig'),
+ message: getErrorMessage(e),
});
return false;
}
};
-export const onDeleteCimConfig = async ({
- deleteResource,
-}: {
- deleteResource: DeleteResourceFuncType;
-}) => {
- try {
- await deleteResource({
- apiVersion: 'agent-install.openshift.io/v1beta1',
- kind: 'AgentServiceConfig',
- metadata: {
- name: 'agent',
- // cluster-scoped resource
- },
- });
- } catch (e) {
- console.error('Failed to delete AgentServiceConfig: ', e);
- }
-};
-*/
// https://access.redhat.com/documentation/en-us/red_hat_advanced_cluster_management_for_kubernetes/2.6/html/multicluster_engine/multicluster_engine_overview#enable-cim
export const onEnableCIM = async ({
t,
setError,
- createResource,
- getResource,
- listResources,
- patchResource,
agentServiceConfig,
platform,
@@ -368,13 +320,10 @@ export const onEnableCIM = async ({
imgVolSizeGiB,
configureLoadBalancer,
+ ciscoIntersightURL,
}: {
t: TFunction;
setError: SetErrorFuncType;
- createResource: CreateResourceFuncType;
- getResource: GetResourceFuncType;
- listResources: ListResourcesFuncType;
- patchResource: PatchResourceFuncType;
agentServiceConfig?: AgentServiceConfigK8sResource;
platform: string;
@@ -384,22 +333,21 @@ export const onEnableCIM = async ({
imgVolSizeGiB: number;
configureLoadBalancer: boolean;
+ ciscoIntersightURL?: string;
}) => {
if (['none', 'baremetal', 'openstack', 'vsphere'].includes(platform.toLocaleLowerCase())) {
- await patchProvisioningConfiguration({ t, setError, patchResource, getResource });
+ await patchProvisioningConfiguration({ t, setError });
}
- if (agentServiceConfig) {
- // console.log('The AgentServiceConfig recently can not be patched. Delete and create instead.');
- } else {
+ if (!agentServiceConfig) {
if (
!(await createAgentServiceConfig({
t,
setError,
- createResource,
dbVolSizeGiB,
fsVolSizeGiB,
imgVolSizeGiB,
+ ciscoIntersightURL,
}))
) {
return false;
@@ -411,16 +359,11 @@ export const onEnableCIM = async ({
if (configureLoadBalancer) {
// Recently No to Yes only (since we do not delete the ingress controller)
- if (await isIngressController(getResource)) {
- // console.log('IngressController already present, we do not patch it.');
+ if (await isIngressController()) {
return true /* Not an error */;
}
- const assistedImageServiceRoute = await getAssistedImageServiceRoute(
- t,
- setError,
- listResources,
- );
+ const assistedImageServiceRoute = await getAssistedImageServiceRoute(t, setError);
if (!assistedImageServiceRoute) {
return false;
}
@@ -431,14 +374,8 @@ export const onEnableCIM = async ({
}
if (
- !(await createIngressController(t, setError, createResource, domain)) ||
- !(await patchAssistedImageServiceRoute(
- t,
- setError,
- patchResource,
- assistedImageServiceRoute,
- domain,
- ))
+ !(await createIngressController(t, setError, domain)) ||
+ !(await patchAssistedImageServiceRoute(t, setError, assistedImageServiceRoute, domain))
) {
return false;
}
diff --git a/libs/ui-lib/lib/cim/components/modals/CimConfiguration/types.ts b/libs/ui-lib/lib/cim/components/modals/CimConfiguration/types.ts
index 448e92cc26..35288a10de 100644
--- a/libs/ui-lib/lib/cim/components/modals/CimConfiguration/types.ts
+++ b/libs/ui-lib/lib/cim/components/modals/CimConfiguration/types.ts
@@ -1,24 +1,12 @@
-import {
- CreateResourceFuncType,
- GetResourceFuncType,
- ListResourcesFuncType,
- PatchResourceFuncType,
-} from '../../../types';
import { AgentServiceConfigK8sResource } from '../../../types/k8s/agent-service-config';
-export type CimConfiguratioProps = {
+export type CimConfigurationValues = {
dbVolSize: number;
- dbVolSizeValidation?: string;
- setDbVolSize: (v: number) => void;
fsVolSize: number;
- fsVolSizeValidation?: string;
- setFsVolSize: (v: number) => void;
imgVolSize: number;
- imgVolSizeValidation?: string;
- setImgVolSize: (v: number) => void;
configureLoadBalancer: boolean;
- configureLoadBalancerInitial: boolean;
- setConfigureLoadBalancer: (v: boolean) => void;
+ addCiscoIntersightUrl: boolean;
+ ciscoIntersightURL: string;
};
export type CimConfigProgressAlertProps = {
@@ -26,12 +14,14 @@ export type CimConfigProgressAlertProps = {
assistedServiceDeploymentUrl: string;
};
-export type CimConfigurationFormProps = CimConfiguratioProps & {
- onClose: () => void;
+export type CimConfigurationFormFieldsProps = {
isEdit: boolean;
isInProgressPeriod: boolean;
docConfigUrl: string;
docConfigAwsUrl: string;
+ platform: string;
+ configureLoadBalancerInitial: boolean;
+ setConfigureLoadBalancerInitial: (value: boolean) => void;
};
export type CimConfigurationModalProps = {
@@ -42,11 +32,6 @@ export type CimConfigurationModalProps = {
docDisconnectedUrl: string;
docConfigUrl: string;
docConfigAwsUrl: string;
-
- createResource: CreateResourceFuncType;
- getResource: GetResourceFuncType;
- listResources: ListResourcesFuncType;
- patchResource: PatchResourceFuncType;
};
export type CimConfigMissingAlertProps = {
diff --git a/libs/ui-lib/lib/cim/hooks/index.tsx b/libs/ui-lib/lib/cim/hooks/index.tsx
index 7d759556d6..843a385735 100644
--- a/libs/ui-lib/lib/cim/hooks/index.tsx
+++ b/libs/ui-lib/lib/cim/hooks/index.tsx
@@ -1 +1,2 @@
export * from './useConfigMaps';
+export * from './useAgentServiceConfig';
diff --git a/libs/ui-lib/lib/cim/hooks/useAgentServiceConfig.tsx b/libs/ui-lib/lib/cim/hooks/useAgentServiceConfig.tsx
new file mode 100644
index 0000000000..db3fd9176c
--- /dev/null
+++ b/libs/ui-lib/lib/cim/hooks/useAgentServiceConfig.tsx
@@ -0,0 +1,15 @@
+import { useK8sWatchResource } from './useK8sWatchResource';
+import { AgentServiceConfigK8sResource } from '../types';
+import { K8sWatchHookProps } from './types';
+
+export const useAgentServiceConfig = (props: K8sWatchHookProps) =>
+ useK8sWatchResource(
+ {
+ groupVersionKind: {
+ group: 'agent-install.openshift.io',
+ kind: 'AgentServiceConfig',
+ version: 'v1beta1',
+ },
+ },
+ props,
+ );
diff --git a/libs/ui-lib/lib/cim/types/index.ts b/libs/ui-lib/lib/cim/types/index.ts
index f59221335b..eaf7ad6b50 100644
--- a/libs/ui-lib/lib/cim/types/index.ts
+++ b/libs/ui-lib/lib/cim/types/index.ts
@@ -1,5 +1,4 @@
export * from './fromOCP';
export * from './k8s';
export * from './metal3';
-export * from './resources';
export * from './models';
diff --git a/libs/ui-lib/lib/cim/types/models.tsx b/libs/ui-lib/lib/cim/types/models.tsx
index bbd4f4e134..57597a6304 100644
--- a/libs/ui-lib/lib/cim/types/models.tsx
+++ b/libs/ui-lib/lib/cim/types/models.tsx
@@ -1,12 +1,56 @@
import { K8sModel } from '@openshift-console/dynamic-plugin-sdk/lib/api/common-types';
export const AgentClusterInstallModel: K8sModel = {
+ kind: 'AgentClusterInstall',
label: 'AgentClusterInstall',
- apiVersion: 'v1beta1',
+ labelPlural: 'AgentClusterInstalls',
plural: 'agentclusterinstalls',
+ apiVersion: 'v1beta1',
+ apiGroup: 'extensions.hive.openshift.io',
+ namespaced: true,
abbr: 'ACI',
+};
+
+export const AgentServiceConfigModel: K8sModel = {
+ kind: 'AgentServiceConfig',
+ label: 'AgentServiceConfig',
+ labelPlural: 'AgentServiceConfigs',
+ plural: 'agentserviceconfigs',
+ apiVersion: 'v1beta1',
+ apiGroup: 'agent-install.openshift.io',
+ namespaced: false,
+ abbr: 'asc',
+};
+
+export const IngressControllerModel: K8sModel = {
+ kind: 'IngressController',
+ label: 'IngressController',
+ labelPlural: 'IngressControllers',
+ plural: 'ingresscontrollers',
+ apiVersion: 'v1',
+ apiGroup: 'operator.openshift.io',
namespaced: true,
- kind: 'AgentClusterInstall',
- labelPlural: 'AgentClusterInstalls',
- apiGroup: 'extensions.hive.openshift.io',
+ abbr: 'ic',
+};
+
+export const RouteModel: K8sModel = {
+ kind: 'Route',
+ label: 'Route',
+ labelPlural: 'Routes',
+ plural: 'routes',
+ apiVersion: 'v1',
+ apiGroup: 'route.openshift.io',
+ namespaced: true,
+ abbr: 'rt',
+};
+
+export const ProvisioningModel: K8sModel = {
+ kind: 'Provisioning',
+ label: 'Provisioning',
+ labelPlural: 'Provisionings',
+ plural: 'provisionings',
+ apiVersion: 'v1alpha1',
+ apiGroup: 'metal3.io',
+ namespaced: false,
+ abbr: 'p',
};
diff --git a/libs/ui-lib/lib/cim/types/resources.ts b/libs/ui-lib/lib/cim/types/resources.ts
deleted file mode 100644
index 5a8aad8bdf..0000000000
--- a/libs/ui-lib/lib/cim/types/resources.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-import { K8sResourceCommon } from '@openshift-console/dynamic-plugin-sdk';
-
-// To conform ACM
-type ResourceType = {
- // status?: any;
- apiVersion: string;
- kind: string;
- metadata?: {
- name?: string;
- namespace?: string;
- resourceVersion?: string;
- creationTimestamp?: string;
- uid?: string;
- annotations?: Record;
- labels?: Record;
- generateName?: string;
- deletionTimestamp?: string;
- selfLink?: string;
- finalizers?: string[];
- ownerReferences?: {
- apiVersion: string;
- blockOwnerDeletion?: boolean;
- controller?: boolean;
- kind: string;
- name: string;
- uid?: string;
- }[];
- // managedFields?: any[];
- };
-};
-
-export type CreateResourceFuncType = (resource: ResourceType) => Promise;
-export type DeleteResourceFuncType = (resource: ResourceType) => Promise;
-export type GetResourceFuncType = (resource: ResourceType) => Promise;
-export type ListResourcesFuncType = (
- resource: { apiVersion: string; kind: string; metadata?: { namespace?: string } },
- labels?: string[],
- query?: Record,
-) => Promise;
-export type ResourcePatch = { op: 'replace' | 'add'; path: string; value: unknown };
-export type PatchResourceFuncType = (
- resource: ResourceType,
- patches: ResourcePatch[],
-) => Promise;
-
-export const convertOCPtoCIMResourceHeader = (res: K8sResourceCommon): ResourceType => ({
- apiVersion: res.apiVersion || '',
- kind: res.kind || '',
- metadata: res.metadata,
-});
diff --git a/libs/ui-lib/lib/common/components/clusterConfiguration/DownloadIso.tsx b/libs/ui-lib/lib/common/components/clusterConfiguration/DownloadIso.tsx
index ec366b2338..3da2a446d2 100644
--- a/libs/ui-lib/lib/common/components/clusterConfiguration/DownloadIso.tsx
+++ b/libs/ui-lib/lib/common/components/clusterConfiguration/DownloadIso.tsx
@@ -23,6 +23,7 @@ export type DownloadISOProps = {
isSNO?: boolean;
fileName?: string;
downloadUrl: string;
+ ciscoUrl?: string;
onClose: () => void;
onReset?: () => void;
docVersion?: string;
@@ -38,13 +39,14 @@ const DownloadIso = ({
isSNO = false,
docVersion,
updateTagsForCiscoIntersight,
+ ciscoUrl,
}: DownloadISOProps) => {
const wgetCommand = `wget -O ${fileName} '${downloadUrl || ''}'`;
const { t } = useTranslation();
const openCiscoIntersightHostsLink = (downloadUrl: string) => {
updateTagsForCiscoIntersight ? updateTagsForCiscoIntersight() : '';
- window.open(getCiscoIntersightLink(downloadUrl), '_blank', 'noopener');
+ window.open(getCiscoIntersightLink(downloadUrl, ciscoUrl), '_blank', 'noopener');
};
return (
diff --git a/libs/ui-lib/lib/common/components/ui/formik/InputField.tsx b/libs/ui-lib/lib/common/components/ui/formik/InputField.tsx
index bdb8d2d6b4..9cdd3cf014 100644
--- a/libs/ui-lib/lib/common/components/ui/formik/InputField.tsx
+++ b/libs/ui-lib/lib/common/components/ui/formik/InputField.tsx
@@ -32,6 +32,7 @@ const InputField: React.FC<
description,
labelInfo,
showErrorMessage = true,
+ type = 'text',
...props
},
ref: React.Ref,
@@ -75,6 +76,7 @@ const InputField: React.FC<
onChange && onChange(event);
}
}}
+ type={type}
/>
{children}
@@ -82,13 +84,20 @@ const InputField: React.FC<
{((showErrorMessage && !isValid) || helperText) && (
- }
- variant={showErrorMessage ? 'error' : 'default'}
- id={showErrorMessage && !isValid ? `${fieldId}-helper-error` : `${fieldId}-helper`}
- >
- {showErrorMessage ? errorMessage : helperText}
-
+ {showErrorMessage && !isValid && (
+ }
+ variant={'error'}
+ id={`${fieldId}-helper-error`}
+ >
+ {errorMessage}
+
+ )}
+ {helperText && (
+
+ {helperText}
+
+ )}
)}
diff --git a/libs/ui-lib/lib/common/components/ui/formik/types.ts b/libs/ui-lib/lib/common/components/ui/formik/types.ts
index 02eeff1d0b..2534991389 100644
--- a/libs/ui-lib/lib/common/components/ui/formik/types.ts
+++ b/libs/ui-lib/lib/common/components/ui/formik/types.ts
@@ -1,11 +1,11 @@
import * as React from 'react';
import {
- TextInputTypes,
FormSelectOptionProps,
TooltipProps,
RadioProps,
FormSelectProps,
DropEvent,
+ TextInputProps,
} from '@patternfly/react-core';
import { DropdownItemProps } from '@patternfly/react-core';
import { FieldValidator, FieldHelperProps } from 'formik';
@@ -64,7 +64,7 @@ export interface SwitchFieldProps extends FieldProps {
}
export interface InputFieldProps extends FieldProps {
- type?: TextInputTypes;
+ type?: TextInputProps['type'];
placeholder?: string;
noDefaultOnChange?: boolean;
onChange?: (event: React.FormEvent) => void;
diff --git a/libs/ui-lib/lib/common/config/docs_links.ts b/libs/ui-lib/lib/common/config/docs_links.ts
index 511a40eb97..b04770a538 100644
--- a/libs/ui-lib/lib/common/config/docs_links.ts
+++ b/libs/ui-lib/lib/common/config/docs_links.ts
@@ -146,8 +146,12 @@ export const FEEDBACK_FORM_LINK =
export const CHANGE_ISO_PASSWORD_FILE_LINK =
'https://raw.githubusercontent.com/openshift/assisted-service/master/docs/change-iso-password.sh';
-export const getCiscoIntersightLink = (downloadIsoUrl: string) =>
- `https://www.intersight.com/an/workflow/workflow-definitions/execute/AddServersFromISO?_workflow_Version=1&IsoUrl=${downloadIsoUrl}`;
+export const getCiscoIntersightLink = (downloadIsoUrl: string, ciscoUrl?: string) => {
+ if (ciscoUrl) {
+ return `${ciscoUrl}?_workflow_Version=1&IsoUrl=${downloadIsoUrl}`;
+ }
+ return `https://www.intersight.com/an/workflow/workflow-definitions/execute/AddServersFromISO?_workflow_Version=1&IsoUrl=${downloadIsoUrl}`;
+};
export const MTV_LINK =
'https://docs.redhat.com/en/documentation/migration_toolkit_for_virtualization/2.7/';