diff --git a/frontend/plugins/mce/console-extensions.ts b/frontend/plugins/mce/console-extensions.ts index edadc66bea7..8e090d52383 100644 --- a/frontend/plugins/mce/console-extensions.ts +++ b/frontend/plugins/mce/console-extensions.ts @@ -1,6 +1,15 @@ /* Copyright Contributors to the Open Cluster Management project */ -import { ContextProvider, Perspective, NavSection, HrefNavItem, RoutePage } from '@openshift-console/dynamic-plugin-sdk' +import { + ContextProvider, + Perspective, + NavSection, + HrefNavItem, + RoutePage, + ResourceDetailsPage, + ResourceNSNavItem, + CreateResource, +} from '@openshift-console/dynamic-plugin-sdk' import { SharedContext } from '../../src/lib/SharedContext' import { EncodedExtension } from '@openshift/dynamic-plugin-sdk-webpack' @@ -92,27 +101,6 @@ const automationsRoute: EncodedExtension = { }, } -// Host Inventory Navigation Item - type: 'console.navigation/href' -const hostInventoryNavItem: EncodedExtension = { - type: 'console.navigation/href', - properties: { - perspective: 'acm', - section: 'mce-infrastructure', - id: 'mce-host-inventory', - name: '%plugin__mce~Host inventory%', - href: '/multicloud/infrastructure/environments', - }, -} - -// Host Inventory Route - type: 'console.page/route' -const hostInventoryRoute: EncodedExtension = { - type: 'console.page/route', - properties: { - path: '/multicloud/infrastructure/environments', - component: { $codeRef: 'environments.default' }, - }, -} - // Virtual Machines Navigation Item - type: 'console.navigation/href' const virtualMachinesNavItem: EncodedExtension = { type: 'console.navigation/href', @@ -154,6 +142,58 @@ const credentialsRoute: EncodedExtension = { }, } +const infraEnvDetails: EncodedExtension = { + type: 'console.page/resource/details', + properties: { + model: { + group: 'agent-install.openshift.io', + version: 'v1beta1', + kind: 'InfraEnv', + }, + component: { $codeRef: 'cim.InfraEnvDetails' }, + }, +} + +const infraEnvRoute: EncodedExtension = { + type: 'console.page/route', + properties: { + path: [ + 'k8s/all-namespaces/agent-install.openshift.io~v1beta1~InfraEnv', + 'k8s/ns/:ns/agent-install.openshift.io~v1beta1~InfraEnv', + ], + component: { $codeRef: 'environments.default' }, + exact: true, + }, +} + +const infraEnvNavItem: EncodedExtension = { + type: 'console.navigation/resource-ns', + properties: { + id: 'mce-host-inventory', + perspective: 'acm', + model: { + group: 'agent-install.openshift.io', + version: 'v1beta1', + kind: 'InfraEnv', + }, + section: 'mce-infrastructure', + name: '%plugin__mce~Host inventory%', + insertAfter: 'mce-automations', + }, +} + +const infraEnvCreate: EncodedExtension = { + type: 'console.resource/create', + properties: { + model: { + group: 'agent-install.openshift.io', + version: 'v1beta1', + kind: 'InfraEnv', + }, + component: { $codeRef: 'cim.CreateInfraEnvPage' }, + }, +} + export const extensions: EncodedExtension[] = [ contextProvider, sharedContext, @@ -163,10 +203,12 @@ export const extensions: EncodedExtension[] = [ clustersRoute, automationsNavItem, automationsRoute, - hostInventoryNavItem, - hostInventoryRoute, virtualMachinesNavItem, virtualMachinesRoute, credentialsNavItem, credentialsRoute, + infraEnvDetails, + infraEnvRoute, + infraEnvNavItem, + infraEnvCreate, ] diff --git a/frontend/plugins/mce/console-plugin-metadata.ts b/frontend/plugins/mce/console-plugin-metadata.ts index 9bef8b010a4..09238f893ca 100644 --- a/frontend/plugins/mce/console-plugin-metadata.ts +++ b/frontend/plugins/mce/console-plugin-metadata.ts @@ -20,6 +20,7 @@ export const pluginMetadata: ConsolePluginBuildMetadata = { environments: '../../src/routes/Infrastructure/InfraEnvironments/InfraEnvironmentsPlugin.tsx', virtualmachines: '../../src/routes/Infrastructure/VirtualMachines/VirtualMachinesPlugin.tsx', credentials: '../../src/routes/Credentials/CredentialsPlugin.tsx', + cim: "../../src/cim/index.ts", }, dependencies: { '@console/pluginAPI': '>=4.15.0', diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index c699d0e3317..5d893f4d44b 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -49,7 +49,6 @@ const Search = lazy(() => import('./routes/Search/Search')) // INFRASTRUCTURE const Clusters = lazy(() => import('./routes/Infrastructure/Clusters/Clusters')) const Automations = lazy(() => import('./routes/Infrastructure/Automations/Automations')) -const InfraEnvironments = lazy(() => import('./routes/Infrastructure/InfraEnvironments/InfraEnvironments')) const VirtualMachines = lazy(() => import('./routes/Infrastructure/VirtualMachines/VirtualMachines')) // GOVERNANCE @@ -191,13 +190,6 @@ const routes: (IRoute | IRouteGroup)[] = [ match: MatchType.SubRoutes, element: , }, - { - title: 'Host inventory', - type: 'route', - path: NavigationPath.infraEnvironments, - match: MatchType.SubRoutes, - element: , - }, { title: 'Virtual machines', type: 'route', diff --git a/frontend/src/NavigationPath.tsx b/frontend/src/NavigationPath.tsx index ac5ef9be1b6..4bfe7630802 100644 --- a/frontend/src/NavigationPath.tsx +++ b/frontend/src/NavigationPath.tsx @@ -118,13 +118,6 @@ export enum NavigationPath { configureDiscovery = '/multicloud/infrastructure/clusters/discovered/configure', createDiscovery = '/multicloud/infrastructure/clusters/discovered/create', - // Infrastructure - Environments - infraEnvironments = '/multicloud/infrastructure/environments', - createInfraEnv = '/multicloud/infrastructure/environments/create', - infraEnvironmentDetails = '/multicloud/infrastructure/environments/details/:namespace/:name', - infraEnvironmentHosts = '/multicloud/infrastructure/environments/details/:namespace/:name/hosts', - infraEnvironmentOverview = '/multicloud/infrastructure/environments/details/:namespace/:name/overview', - // Infrastructure - Automations ansibleAutomations = '/multicloud/infrastructure/automations', addAnsibleAutomation = '/multicloud/infrastructure/automations/add', diff --git a/frontend/src/cim/index.ts b/frontend/src/cim/index.ts new file mode 100644 index 00000000000..ba8255ef815 --- /dev/null +++ b/frontend/src/cim/index.ts @@ -0,0 +1 @@ +export { CreateInfraEnvPage, InfraEnvDetails } from '@openshift-assisted/ui-lib/cim' diff --git a/frontend/src/hooks/use-available-hosts-alert.tsx b/frontend/src/hooks/use-available-hosts-alert.tsx index c0ba121f39c..6b0b1202979 100644 --- a/frontend/src/hooks/use-available-hosts-alert.tsx +++ b/frontend/src/hooks/use-available-hosts-alert.tsx @@ -5,7 +5,6 @@ import { getAgentsForSelection } from '@openshift-assisted/ui-lib/cim' import { useRecoilValue, useSharedAtoms } from '../shared-recoil' import { Trans, useTranslation } from '../lib/acm-i18next' -import { NavigationPath } from '../NavigationPath' const useNoAvailableHostsAlert = ( controlPlaneType: 'hosted' | 'standalone' @@ -25,12 +24,12 @@ const useNoAvailableHostsAlert = ( controlPlaneType === 'standalone' ? ( {} }} + components={{ a: {} }} /> ) : ( {} }} + components={{ a: {} }} /> ), } @@ -41,7 +40,7 @@ const useNoAvailableHostsAlert = ( {} }} + components={{ a: {} }} /> ), } diff --git a/frontend/src/logos/OnPremiseBannerIcon.svg b/frontend/src/logos/OnPremiseBannerIcon.svg deleted file mode 100644 index 5c1d8b0ef53..00000000000 --- a/frontend/src/logos/OnPremiseBannerIcon.svg +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/CreateCluster/CreateCluster.tsx b/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/CreateCluster/CreateCluster.tsx index 4f1c0a60059..ddb21c94743 100644 --- a/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/CreateCluster/CreateCluster.tsx +++ b/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/CreateCluster/CreateCluster.tsx @@ -507,7 +507,7 @@ export default function CreateCluster(props: { infrastructureType: ClusterInfras title: t('cim.infra.missing.warning.title'), text: t('cim.infra.missing.warning.text'), linkText: t('cim.infra.manage.link'), - linkTo: NavigationPath.infraEnvironments, + linkTo: '/k8s/all-namespaces/agent-install.openshift.io~v1beta1~InfraEnv', }) } else { setWarning(undefined) diff --git a/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/CreateCluster/components/assisted-installer/hypershift/NetworkForm.tsx b/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/CreateCluster/components/assisted-installer/hypershift/NetworkForm.tsx index 16af483f60e..e78ab6dcf05 100644 --- a/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/CreateCluster/components/assisted-installer/hypershift/NetworkForm.tsx +++ b/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/CreateCluster/components/assisted-installer/hypershift/NetworkForm.tsx @@ -5,7 +5,6 @@ import { FormikProps } from 'formik' import isEqual from 'lodash/isEqual' import { HypershiftAgentContext } from './HypershiftAgentContext' -import { isBMPlatform } from '../../../../../../InfraEnvironments/utils' import { useSharedAtoms, useRecoilValue } from '../../../../../../../../shared-recoil' import { getTemplateValue } from '../utils' import { defaultHostPrefix, defaultPodCIDR, defaultServiceCIDR } from './constants' @@ -141,7 +140,7 @@ const NetworkForm: React.FC = ({ control, handleChange, templa const initialValues: NetworkFormValues = React.useMemo( () => - getDefaultNetworkFormValues(templateYAML, isBMPlatform(infrastructures[0]), isAdvancedNetworking, sshPublicKey), + getDefaultNetworkFormValues(templateYAML, ['BareMetal', 'None', 'OpenStack', 'VSphere'].includes(infrastructures[0]?.status?.platform || ''), isAdvancedNetworking, sshPublicKey), [templateYAML, infrastructures, isAdvancedNetworking, sshPublicKey] ) diff --git a/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/CreateCluster/components/assisted-installer/utils.test.ts b/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/CreateCluster/components/assisted-installer/utils.test.ts index e5d70325833..c4db9284273 100644 --- a/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/CreateCluster/components/assisted-installer/utils.test.ts +++ b/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/CreateCluster/components/assisted-installer/utils.test.ts @@ -5,7 +5,6 @@ import { AgentK8sResource, BareMetalHostK8sResource, ClusterDeploymentK8sResource, - InfraEnvK8sResource, } from '@openshift-assisted/ui-lib/cim' import { getDefault, @@ -14,7 +13,6 @@ import { getDeleteHostAction, setProvisionRequirements, onHostsNext, - onEditProxy, useProvisioningConfiguration, onEditFinish, } from './utils' @@ -185,25 +183,6 @@ describe('onHostsNext', () => { }) }) -describe('onEditProxy', () => { - it('enables proxy', () => { - const infraEnv: InfraEnvK8sResource = { - metadata: { - name: 'foo', - namespace: 'bar', - }, - } - onEditProxy( - { - httpProxy: 'foo', - httpsProxy: 'bar', - noProxy: 'baz', - }, - infraEnv - ) - }) -}) - describe('onEditFinish', () => { afterEach(() => { jest.clearAllMocks() diff --git a/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/CreateCluster/components/assisted-installer/utils.ts b/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/CreateCluster/components/assisted-installer/utils.ts index 82fe28694dc..bdec1db99a7 100644 --- a/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/CreateCluster/components/assisted-installer/utils.ts +++ b/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/CreateCluster/components/assisted-installer/utils.ts @@ -1,13 +1,10 @@ /* Copyright Contributors to the Open Cluster Management project */ /* eslint-disable react-hooks/exhaustive-deps */ -import { useCallback, useMemo, useState, useEffect, useContext } from 'react' -import { generatePath } from 'react-router-dom-v5-compat' +import { useCallback, useMemo, useState, useEffect } from 'react' import { isEqual } from 'lodash' import { getAnnotationsFromAgentSelector, AGENT_BMH_NAME_LABEL_KEY, - getBareMetalHostCredentialsSecret, - getBareMetalHost, isAgentOfCluster, BMH_HOSTNAME_ANNOTATION, ClusterDeploymentK8sResource, @@ -16,36 +13,15 @@ import { ConfigMapK8sResource, InfraEnvK8sResource, NMStateK8sResource, - AddBmcValues, - DiscoveryImageFormValues, } from '@openshift-assisted/ui-lib/cim' import { useTranslation } from '../../../../../../../lib/acm-i18next' -import { - ClusterImageSet, - listClusterImageSets, - ManagedClusterApiVersion, - ManagedClusterKind, - KlusterletAddonConfigApiVersion, - KlusterletAddonConfigKind, - IResource, - ClusterCurator, -} from '../../../../../../../resources' -import { - patchResource, - createResource, - getResource, - listResources, - createResources, -} from '../../../../../../../resources/utils' -import { NavigationPath } from '../../../../../../../NavigationPath' -import { ModalProps } from './types' +import { ClusterImageSet, listClusterImageSets, IResource, ClusterCurator } from '../../../../../../../resources' +import { patchResource, getResource } from '../../../../../../../resources/utils' import { deleteResources } from '../../../../../../../lib/delete-resources' import { BulkActionModalProps } from '../../../../../../../components/BulkActionModal' import { AgentK8sResource, BareMetalHostK8sResource } from '@openshift-assisted/ui-lib/cim' import { useSharedAtoms, useRecoilValue } from '../../../../../../../shared-recoil' -import { K8sResourceCommon } from '@openshift-console/dynamic-plugin-sdk' -import { PluginContext } from '../../../../../../../lib/PluginContext' type OnHostsNext = { values: any @@ -420,31 +396,6 @@ export const findInfraEnvByClusterRef = ( return infraEnvs.find((ie) => ie.spec?.clusterRef?.name === name && ie.spec?.clusterRef?.namespace === namespace) } -export const onApproveAgent = (agent: AgentK8sResource) => - patchResource(agent as IResource, [ - { - op: 'replace', - path: '/spec/approved', - value: true, - }, - ]).promise as Promise - -export const getClusterDeploymentLink = ({ name, namespace }: { name: string; namespace: string }) => - generatePath(NavigationPath.clusterDetails, { name, namespace }) - -export const fetchSecret = (namespace: string, name: string) => - getResource({ apiVersion: 'v1', kind: 'Secret', metadata: { namespace, name } }).promise - -export const fetchManagedClusters = () => - listResources({ apiVersion: ManagedClusterApiVersion, kind: ManagedClusterKind }).promise as Promise< - K8sResourceCommon[] - > - -export const fetchKlusterletAddonConfig = () => - listResources({ apiVersion: KlusterletAddonConfigApiVersion, kind: KlusterletAddonConfigKind }).promise as Promise< - K8sResourceCommon[] - > - export const getDeleteHostAction = ( bareMetalHosts: BareMetalHostK8sResource[], @@ -539,75 +490,6 @@ export const useOnDeleteHost = ( ) } -export const onSaveBMH = - (editModal: ModalProps | undefined) => async (values: AddBmcValues, nmState?: NMStateK8sResource) => { - let newSecret - if (editModal?.secret) { - const patches: any[] = [] - appendPatch(patches, '/data/username', btoa(values.username), editModal.secret.data?.username) - appendPatch(patches, '/data/password', btoa(values.password), editModal.secret.data?.password) - if (patches.length) { - await patchResource(editModal.secret as IResource, patches).promise - } - } else { - const secret = getBareMetalHostCredentialsSecret(values, editModal?.bmh?.metadata?.namespace || '') - newSecret = await createResource(secret).promise - } - - if (editModal?.nmState) { - const patches: any[] = [] - appendPatch(patches, '/spec/config', nmState?.spec?.config, editModal.nmState.spec?.config) - appendPatch(patches, '/spec/interfaces', nmState?.spec?.interfaces || [], editModal.nmState.spec?.interfaces) - if (patches.length) { - await patchResource(editModal.nmState as IResource, patches).promise - } - } else if (nmState) { - await createResource(nmState).promise - } - - if (editModal?.bmh) { - const patches: any[] = [] - appendPatch( - patches, - `/metadata/annotations/${BMH_HOSTNAME_ANNOTATION.replace('/', '~1')}`, - values.hostname, - editModal.bmh.metadata?.annotations?.[BMH_HOSTNAME_ANNOTATION] - ) - appendPatch(patches, '/spec/bmc/address', values.bmcAddress, editModal.bmh.spec?.bmc?.address) - appendPatch( - patches, - '/spec/bmc/disableCertificateVerification', - values.disableCertificateVerification, - editModal.bmh.spec?.bmc?.disableCertificateVerification.toString() - ) - appendPatch(patches, '/spec/bootMACAddress', values.bootMACAddress, editModal.bmh.spec?.bootMACAddress) - appendPatch(patches, '/spec/online', values.online, editModal.bmh.spec?.online.toString()) - - if (newSecret) { - appendPatch( - patches, - '/spec/bmc/credentialsName', - newSecret.metadata.name, - editModal.bmh.spec?.bmc?.credentialsName - ) - } - if (patches.length) { - await patchResource(editModal.bmh as IResource, patches).promise - } - } - } - -export const getOnCreateBMH = - (infraEnv: InfraEnvK8sResource) => async (values: AddBmcValues, nmState?: NMStateK8sResource) => { - const secret = getBareMetalHostCredentialsSecret(values, infraEnv.metadata?.namespace || '') - const secretRes = await createResource(secret).promise - if (nmState) { - await createResource(nmState).promise - } - const bmh: BareMetalHostK8sResource = getBareMetalHost(values, infraEnv, secretRes) - return createResource(bmh as IResource).promise as InfraEnvK8sResource - } - export const onChangeHostname = async (agent: AgentK8sResource, hostname: string) => patchResource(agent as IResource, [ { @@ -659,142 +541,6 @@ export const useClusterImages = () => { return clusterImages } -const refetchInfraEnv = async (infraEnv: InfraEnvK8sResource) => - await getResource({ - apiVersion: infraEnv.apiVersion!, - kind: infraEnv.kind!, - metadata: { namespace: infraEnv.metadata?.namespace, name: infraEnv.metadata?.name }, - }).promise - -const sleep = async (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)) - -export const getOnSaveISOParams = (infraEnv: InfraEnvK8sResource) => async (values: DiscoveryImageFormValues) => { - const patches: any[] = [] - if (values.sshPublicKey) { - appendPatch(patches, '/spec/sshAuthorizedKey', values.sshPublicKey, infraEnv.spec?.sshAuthorizedKey) - } else if (infraEnv.spec?.sshAuthorizedKey) { - patches.push({ - op: 'remove', - path: '/spec/sshAuthorizedKey', - }) - } - - const proxy = values.enableProxy - ? { - httpProxy: values.httpProxy, - httpsProxy: values.httpsProxy, - noProxy: values.noProxy, - } - : undefined - - if (proxy) { - appendPatch(patches, '/spec/proxy', proxy, infraEnv.spec?.proxy) - } else if (infraEnv.spec?.proxy) { - patches.push({ - op: 'remove', - path: '/spec/proxy', - }) - } - - if (values.imageType) { - appendPatch(patches, '/spec/imageType', values.imageType, infraEnv.spec?.imageType) - } - // TODO(mlibra): Why is oldIsoCreatedTimestamp not from a condition? I would expect infraEnv.status?.conditions?.find((condition) => condition.type === 'ImageCreated') - const oldIsoCreatedTimestamp = infraEnv.status?.createdTime - - if (patches.length) { - await patchResource(infraEnv as IResource, patches).promise - // Keep the handleIsoConfigSubmit() promise going until ISO is regenerated - the Loading status will be present in the meantime - // TODO(mlibra): there is MGMT-7255 WIP to add image streaming service when this waiting will not be needed and following code can be removed, just relying on infraEnv's isoDownloadURL to be always up-to-date. - // For that reason we keep following polling logic here and not moving it to the calling components where it could rely on a watcher. - let polledInfraEnv: InfraEnvK8sResource = await refetchInfraEnv(infraEnv) - let maxPollingCounter = 10 - while (polledInfraEnv.status?.createdTime === oldIsoCreatedTimestamp && --maxPollingCounter) { - await sleep(5 * 1000) - polledInfraEnv = await refetchInfraEnv(infraEnv) - } - // quit anyway ... - } -} - -export const saveSSHKey = async (values: any, infraEnv: InfraEnvK8sResource) => { - const patches: any[] = [] - appendPatch(patches, '/spec/sshAuthorizedKey', values.sshPublicKey, infraEnv.spec?.sshAuthorizedKey) - if (patches.length) { - return patchResource(infraEnv as IResource, patches).promise - } -} - -export const onEditProxy = async (values: any, infraEnv: InfraEnvK8sResource) => { - const patches: any[] = [] - const proxySettings: { - httpProxy?: string - httpsProxy?: string - noProxy?: string - } = {} - if (values.httpProxy) { - proxySettings.httpProxy = values.httpProxy - } - if (values.httpsProxy) { - proxySettings.httpsProxy = values.httpsProxy - } - if (values.noProxy) { - proxySettings.noProxy = values.noProxy - } - appendPatch(patches, '/spec/proxy', proxySettings, infraEnv.spec?.proxy) - if (patches.length) { - return patchResource(infraEnv as IResource, patches).promise - } -} - -export const savePullSecret = (values: any, infraEnv: InfraEnvK8sResource) => { - const secret = { - apiVersion: 'v1', - kind: 'Secret', - metadata: { - namespace: infraEnv.metadata?.namespace, - name: infraEnv.spec?.pullSecretRef?.name, - }, - } - if (values.createSecret) { - return createResource({ - ...secret, - data: { - '.dockerconfigjson': btoa(values.pullSecret), - }, - type: 'kubernetes.io/dockerconfigjson', - }).promise - } else { - return patchResource(secret, [ - { - op: 'replace', - path: '/data/.dockerconfigjson', - value: btoa(values.pullSecret), - }, - ]).promise - } -} - -export const onEditNtpSources = (values: any, infraEnv: InfraEnvK8sResource) => { - const patches: any[] = [] - if (values.enableNtpSources === 'auto') { - if (infraEnv.spec?.additionalNTPSources) { - patches.push({ - op: 'remove', - path: '/spec/additionalNTPSources', - }) - } - } else { - appendPatch( - patches, - '/spec/additionalNTPSources', - (values.additionalNtpSources as string).split(',').map((s) => s.trim()), - infraEnv.spec?.additionalNTPSources - ) - } - return patchResource(infraEnv as IResource, patches).promise as Promise -} - export const onMassDeleteHost = ( agent?: AgentK8sResource, bmh?: BareMetalHostK8sResource, @@ -819,10 +565,6 @@ export const fetchInfraEnv = (name: string, namespace: string) => getResource({ apiVersion: 'agent-install.openshift.io/v1beta1', kind: 'InfraEnv', metadata: { namespace, name } }) .promise -export const importYaml = (yamlContent: unknown) => { - return createResources(yamlContent as IResource[]) -} - // Simple string search is _so far_ enough. // Full key-path support would be ineffective when not actually needed. export const getTemplateValue = (yaml: string, simpleKey: string, defaultValue: string, index = 0) => { @@ -857,25 +599,6 @@ export const onSetInstallationDiskId = (agent: AgentK8sResource, diskId: string) ]).promise as Promise } -export const useProvisioningConfiguration = (): [K8sResourceCommon | null, boolean, unknown] => { - const { - ocpApi: { useK8sWatchResource }, - } = useContext(PluginContext) - const [config, loaded, error] = useK8sWatchResource({ - name: 'provisioning-configuration', - groupVersionKind: { - group: 'metal3.io', - version: 'v1alpha1', - kind: 'Provisioning', - }, - }) - const _error = error as { json?: { reason?: string } } - if (_error?.json?.reason === 'NotFound') { - return [null, true, null] - } - return [config, loaded || !!error, error] -} - export const onEditFinish = async ( agentClusterInstall: AgentClusterInstallK8sResource, clusterCurator: ClusterCurator | undefined diff --git a/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/components/OnboardingModal.tsx b/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/components/OnboardingModal.tsx index 4faa20280f3..05da6390d3c 100644 --- a/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/components/OnboardingModal.tsx +++ b/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/components/OnboardingModal.tsx @@ -43,7 +43,7 @@ export function OnboardingModal(props: IOnboardingModalProps) { id: 'onboardingdiscoverbutton', icon: , text: t('Discover hosts to create host inventory'), - link: NavigationPath.infraEnvironments, + link: '/k8s/all-namespaces/agent-install.openshift.io~v1beta1~InfraEnv', style: { paddingRight: '24px', }, diff --git a/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/components/cim/EditAICluster.tsx b/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/components/cim/EditAICluster.tsx index eed0959e524..d7bdd9e05f5 100644 --- a/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/components/cim/EditAICluster.tsx +++ b/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/components/cim/EditAICluster.tsx @@ -5,17 +5,13 @@ import { PathParam, generatePath, useLocation, useNavigate, useParams } from 're import { ACM_ENABLED_FEATURES, AgentK8sResource, - BareMetalHostK8sResource, ClusterDeploymentDetailsValues, ClusterDeploymentWizard, ClusterDeploymentWizardStepsType, ClusterImageSetK8sResource, - EditAgentModal, FeatureGateContextProvider, LoadingState, - getAgentsHostsNames, isAgentOfInfraEnv, - onAgentChangeHostname, } from '@openshift-assisted/ui-lib/cim' import { PageSection, Switch } from '@patternfly/react-core' import { AcmErrorBoundary, AcmPageContent, AcmPage, AcmPageHeader } from '../../../../../../ui-components' @@ -23,34 +19,19 @@ import { AcmErrorBoundary, AcmPageContent, AcmPage, AcmPageHeader } from '../../ import { IResource } from '../../../../../../resources' import { patchResource } from '../../../../../../resources/utils' import { - fetchSecret, - getClusterDeploymentLink, - getOnCreateBMH, - getOnSaveISOParams, - onApproveAgent, onDiscoveryHostsNext, onHostsNext, - onChangeHostname, - onSaveBMH, onSaveNetworking, useClusterDeployment, useAgentClusterInstall, fetchInfraEnv, - fetchManagedClusters, - fetchKlusterletAddonConfig, - useOnDeleteHost, useAssistedServiceConfigMap, useClusterDeploymentInfraEnv, - importYaml, onSetInstallationDiskId, - useProvisioningConfiguration, onEditFinish, - onChangeBMHHostname, } from '../../CreateCluster/components/assisted-installer/utils' import { NavigationPath } from '../../../../../../NavigationPath' import { useTranslation } from '../../../../../../lib/acm-i18next' -import { getInfraEnvNMStates } from '../../../../InfraEnvironments/utils' -import { BulkActionModal, BulkActionModalProps } from '../../../../../../components/BulkActionModal' import { useSharedAtoms, useRecoilValue } from '../../../../../../shared-recoil' import { DOC_VERSION } from '../../../../../../lib/doc-util' @@ -63,12 +44,10 @@ const EditAICluster: React.FC = () => { const { t } = useTranslation() const [patchingHoldInstallation, setPatchingHoldInstallation] = useState(true) const navigate = useNavigate() - const { agentsState, clusterImageSetsState, nmStateConfigsState, clusterCuratorsState, bareMetalHostsState } = + const { agentsState, clusterImageSetsState, clusterCuratorsState, bareMetalHostsState } = useSharedAtoms() - const [editAgent, setEditAgent] = useState() const clusterImageSets = useRecoilValue(clusterImageSetsState) const agents = useRecoilValue(agentsState) - const nmStateConfigs = useRecoilValue(nmStateConfigsState) const clusterCurators = useRecoilValue(clusterCuratorsState) const bareMetalHosts = useRecoilValue(bareMetalHostsState) const aiConfigMap = useAssistedServiceConfigMap() @@ -80,12 +59,7 @@ const EditAICluster: React.FC = () => { clusterDeployment?.metadata?.namespace! ) - const infraNMStates = useMemo(() => getInfraEnvNMStates(nmStateConfigs, infraEnv), [nmStateConfigs, infraEnv]) - - const usedHostnames = useMemo(() => getAgentsHostsNames(agents), [agents]) - const [isPreviewOpen, setPreviewOpen] = useState(!!localStorage.getItem(TEMPLATE_EDITOR_OPEN_COOKIE)) - const provisioningConfigResult = useProvisioningConfiguration() const onSaveDetails = (values: ClusterDeploymentDetailsValues) => { return patchResource(agentClusterInstall as IResource, [ @@ -107,15 +81,7 @@ const EditAICluster: React.FC = () => { [agents, infraEnv] ) - const [bulkModalProps, setBulkModalProps] = useState< - BulkActionModalProps | { open: false } - >({ open: false }) - const onDeleteHost = useOnDeleteHost(setBulkModalProps, [], agentClusterInstall, infraNMStates) - const hostActions = { - onEditHost: (agent: AgentK8sResource) => { - setEditAgent(agent) - }, onEditRole: (agent: AgentK8sResource, role: string | undefined) => { return patchResource(agent as IResource, [ { @@ -125,7 +91,6 @@ const EditAICluster: React.FC = () => { }, ]).promise as Promise }, - onDeleteHost, onSetInstallationDiskId, } @@ -195,7 +160,6 @@ const EditAICluster: React.FC = () => { - {...bulkModalProps} /> {/* @ts-expect-error @openshift-assisted/ui-lib needs React 18 updates */} { onSaveHostsSelection={(values) => onHostsNext({ values, clusterDeployment, agents, agentClusterInstall }) } - onApproveAgent={onApproveAgent} - onChangeHostname={onChangeHostname} - onChangeBMHHostname={onChangeBMHHostname} - onSaveBMH={onSaveBMH} - onCreateBMH={ - infraEnv ? getOnCreateBMH(infraEnv) : undefined - } /* AI Flow specific. Not called for CIM. */ - onSaveISOParams={ - infraEnv ? getOnSaveISOParams(infraEnv) : undefined /* AI Flow specific. Not called for CIM. */ - } onSaveHostsDiscovery={() => onDiscoveryHostsNext({ clusterDeployment, @@ -229,9 +183,6 @@ const EditAICluster: React.FC = () => { agentClusterInstall, }) } - fetchSecret={fetchSecret} - infraNMStates={infraNMStates} - getClusterDeploymentLink={getClusterDeploymentLink} hostActions={hostActions} onFinish={async () => { const aci = await onEditFinish(agentClusterInstall, clusterCurator) @@ -244,21 +195,9 @@ const EditAICluster: React.FC = () => { fetchInfraEnv={fetchInfraEnv} isPreviewOpen={isPreviewOpen} setPreviewOpen={setPreviewOpen} - fetchManagedClusters={fetchManagedClusters} - fetchKlusterletAddonConfig={fetchKlusterletAddonConfig} - onCreateBmcByYaml={importYaml} docVersion={DOC_VERSION} - provisioningConfigResult={provisioningConfigResult} isNutanix={isNutanix} /> - {editAgent && ( - setEditAgent(undefined)} - onSave={onAgentChangeHostname([editAgent], bareMetalHosts, onChangeHostname, onChangeBMHHostname)} - /> - )} diff --git a/frontend/src/routes/Infrastructure/InfraEnvironments/CreateInfraEnv.css b/frontend/src/routes/Infrastructure/InfraEnvironments/CreateInfraEnv.css deleted file mode 100644 index 1997dbf6735..00000000000 --- a/frontend/src/routes/Infrastructure/InfraEnvironments/CreateInfraEnv.css +++ /dev/null @@ -1,3 +0,0 @@ -.create-infra-env__content { - padding: 0; -} diff --git a/frontend/src/routes/Infrastructure/InfraEnvironments/CreateInfraEnv.tsx b/frontend/src/routes/Infrastructure/InfraEnvironments/CreateInfraEnv.tsx deleted file mode 100644 index 6bb82aae38a..00000000000 --- a/frontend/src/routes/Infrastructure/InfraEnvironments/CreateInfraEnv.tsx +++ /dev/null @@ -1,150 +0,0 @@ -/* Copyright Contributors to the Open Cluster Management project */ -import { AcmErrorBoundary, AcmPage, AcmPageContent, AcmPageHeader } from '../../../ui-components' -import { PageSection } from '@patternfly/react-core' -import Handlebars from 'handlebars' -import { useState } from 'react' -import { useTranslation } from '../../../lib/acm-i18next' -import MonacoEditor from 'react-monaco-editor' -import { generatePath, useNavigate } from 'react-router-dom-v5-compat' -import TemplateEditor from '../../../components/TemplateEditor' -import { NavigationPath } from '../../../NavigationPath' -import infraEnvTemplate from './infraenv-template.hbs' -import InfraEnvForm, { Portals } from './InfraEnvForm' - -// include monaco editor -import 'monaco-editor/esm/vs/editor/editor.all.js' -import 'monaco-editor/esm/vs/basic-languages/yaml/yaml.contribution.js' -import '../../Applications/CreateApplication/Subscription/style.css' -import { createProject, IResource } from '../../../resources' -import { createResource } from '../../../resources/utils' -import { deleteResources } from '../../../lib/delete-resources' - -import './CreateInfraEnv.css' - -const controlData = [ - { - name: 'creation.ocp.cloud.connection', - tooltip: 'tooltip.creation.ocp.cloud.connection', - id: 'ai', - type: 'custom', - component: , - providerId: 'aiNetwork', - }, -] - -const CreateInfraEnv: React.FC = () => { - const template = Handlebars.compile(infraEnvTemplate) - Handlebars.registerHelper('checkNtpSources', (enable, sources) => enable && sources?.length > 0) - const navigate = useNavigate() - const { t } = useTranslation() - const { t: tEditor } = useTranslation() - const i18n = (key: any, arg: any) => { - return tEditor(key, arg) - } - - const switches = ( -
-
-
- ) - - // create button - const [creationStatus, setCreationStatus] = useState<{ - status: string - messages: any[] | undefined - }>() - - const createInfraEnv = async (resourceJSON: { createResources: any[] }) => { - if (resourceJSON) { - setCreationStatus({ status: 'IN_PROGRESS', messages: [] }) - const { createResources } = resourceJSON - const infraEnv = createResources.find((r) => r.kind === 'InfraEnv') - try { - await createProject(infraEnv.metadata.namespace).promise - } catch (err) { - if ((err as unknown as { code: number }).code !== 409) { - setCreationStatus({ - status: 'ERROR', - messages: [{ message: (err as unknown as Error).message }], - }) - return - } - } - - const promises = createResources.map((resource: any) => createResource(resource).promise) - // All resources must be resolved - const responses = await Promise.allSettled(promises) - const error = responses.find((result) => result.status === 'rejected') - - if (error) { - const resourcesToDelete = createResources - .filter((r) => r.apiVersion && r.kind && r.metadata?.name && r.metadata?.namespace) - .map( - (r) => - ({ - apiVersion: r.apiVersion, - kind: r.kind, - metadata: { name: r.metadata.name, namespace: r.metadata.namespace }, - }) as IResource - ) - try { - await deleteResources(resourcesToDelete).promise - } finally { - setCreationStatus({ - status: 'ERROR', - messages: [{ message: (error as PromiseRejectedResult).reason?.message }], - }) - } - } else { - setCreationStatus({ status: 'DONE', messages: [] }) - navigate( - generatePath(NavigationPath.infraEnvironmentOverview, { - namespace: infraEnv.metadata.namespace, - name: infraEnv.metadata.name, - }) - ) - } - } - } - - return ( - - } - > - - - - } - controlData={controlData} - template={template} - portals={Portals} - createControl={{ - createResource: createInfraEnv, - cancelCreate: () => navigate(NavigationPath.infraEnvironments), - pauseCreate: () => {}, - creationStatus: creationStatus?.status, - creationMsg: creationStatus?.messages, - }} - logging={process.env.NODE_ENV !== 'production'} - i18n={i18n} - /> - - - - - ) -} - -export default CreateInfraEnv diff --git a/frontend/src/routes/Infrastructure/InfraEnvironments/Details/DetailsTab.tsx b/frontend/src/routes/Infrastructure/InfraEnvironments/Details/DetailsTab.tsx deleted file mode 100644 index 82a7ac10b17..00000000000 --- a/frontend/src/routes/Infrastructure/InfraEnvironments/Details/DetailsTab.tsx +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright Contributors to the Open Cluster Management project */ -import { AcmPageContent } from '../../../../ui-components' -import { Card, CardBody, PageSection } from '@patternfly/react-core' -import { DOC_VERSION } from '../../../../lib/doc-util' -import { - fetchSecret, - savePullSecret, - saveSSHKey, - onEditNtpSources, - onEditProxy, -} from '../../Clusters/ManagedClusters/CreateCluster/components/assisted-installer/utils' -import { EnvironmentDetails, EnvironmentErrors } from '@openshift-assisted/ui-lib/cim' -import { useInfraEnvironmentDetailsContext } from './InfraEnvironmentDetailsPage' - -const DetailsTab: React.FC = () => { - const { infraEnv, infraAgents, bareMetalHosts } = useInfraEnvironmentDetailsContext() - return ( - - - - - - - - - - - ) -} - -export default DetailsTab diff --git a/frontend/src/routes/Infrastructure/InfraEnvironments/Details/HostsTab.tsx b/frontend/src/routes/Infrastructure/InfraEnvironments/Details/HostsTab.tsx deleted file mode 100644 index 9c46d181b72..00000000000 --- a/frontend/src/routes/Infrastructure/InfraEnvironments/Details/HostsTab.tsx +++ /dev/null @@ -1,111 +0,0 @@ -/* Copyright Contributors to the Open Cluster Management project */ -import { useState, useMemo } from 'react' -import { Card, CardBody, PageSection } from '@patternfly/react-core' -import { AcmPageContent } from '../../../../ui-components' -import { BulkActionModal, BulkActionModalProps } from '../../../../components/BulkActionModal' -import { DOC_VERSION } from '../../../../lib/doc-util' -import { useOnUnbindHost } from '../../Clusters/ManagedClusters/CreateCluster/components/assisted-installer/unbindHost' -import { - fetchSecret, - getClusterDeploymentLink, - onApproveAgent, - onChangeBMHHostname, - onMassDeleteHost, - onChangeHostname, - onSaveBMH, - useAssistedServiceConfigMap, - useOnDeleteHost, -} from '../../Clusters/ManagedClusters/CreateCluster/components/assisted-installer/utils' -import { useRecoilValue, useSharedAtoms } from '../../../../shared-recoil' -import { - AgentAlerts, - AgentK8sResource, - BareMetalHostK8sResource, - EditAgentModal, - EditBMHModal, - InfoAndTroubleshootingNotification, - InfraEnvAgentTable, - getAgentsHostsNames, - onAgentChangeHostname, -} from '@openshift-assisted/ui-lib/cim' -import { useInfraEnvironmentDetailsContext } from './InfraEnvironmentDetailsPage' - -const HostsTab: React.FC = () => { - const { - infraEnv, - infraAgents, - agentClusterInstalls, - bareMetalHosts, - infraNMStates = [], - } = useInfraEnvironmentDetailsContext() - const { agentMachinesState } = useSharedAtoms() - const agentMachines = useRecoilValue(agentMachinesState) - const [editBMH, setEditBMH] = useState() - const [editAgent, setEditAgent] = useState() - const [bulkModalProps, setBulkModalProps] = useState< - BulkActionModalProps | { open: false } - >({ open: false }) - const onDeleteHost = useOnDeleteHost(setBulkModalProps, bareMetalHosts, undefined, infraNMStates) - const onUnbindHost = useOnUnbindHost(setBulkModalProps, undefined, undefined) - - const usedHostnames = useMemo(() => getAgentsHostsNames(infraAgents, bareMetalHosts), [bareMetalHosts, infraAgents]) - const assistedServiceConfigMap = useAssistedServiceConfigMap() - - return ( - <> - {...bulkModalProps} /> - - - - - {!!assistedServiceConfigMap && ( - - )} - -
- - - - setEditBMH(undefined)} - onEdit={onSaveBMH} - fetchSecret={fetchSecret} - usedHostnames={usedHostnames} - /> - {editAgent && ( - setEditAgent(undefined)} - onSave={onAgentChangeHostname([editAgent], bareMetalHosts, onChangeHostname, onChangeBMHHostname)} - /> - )} - - -
-
- - ) -} - -export default HostsTab diff --git a/frontend/src/routes/Infrastructure/InfraEnvironments/Details/InfraEnvironmentDetailsPage.test.tsx b/frontend/src/routes/Infrastructure/InfraEnvironments/Details/InfraEnvironmentDetailsPage.test.tsx deleted file mode 100644 index b06835d3860..00000000000 --- a/frontend/src/routes/Infrastructure/InfraEnvironments/Details/InfraEnvironmentDetailsPage.test.tsx +++ /dev/null @@ -1,120 +0,0 @@ -/* Copyright Contributors to the Open Cluster Management project */ -import { render } from '@testing-library/react' -import { cloneDeep } from 'lodash' -import set from 'lodash/set' -import { MemoryRouter, Route, Routes } from 'react-router-dom-v5-compat' -import { RecoilRoot } from 'recoil' -import { infraEnvironmentsState, nmStateConfigsState } from '../../../../atoms' -import { nockGet, nockIgnoreApiPaths, nockPatch } from '../../../../lib/nock-util' -import { clickByText, clickHostAction, waitForNocks, waitForNotText, waitForText } from '../../../../lib/test-util' -import { NavigationPath } from '../../../../NavigationPath' -import { IResource } from '../../../../resources/resource' -import { mockNMStateConfig } from '../../Clusters/ManagedClusters/components/cim/EditAICluster.sharedmocks' -import { infraEnvName, mockInfraEnv1, mockPullSecret } from '../../../../test-helpers/infraEnvName' -import { InfraEnvK8sResource } from '@openshift-assisted/ui-lib/cim' -import * as dynamicPluginSdk from '@openshift-console/dynamic-plugin-sdk' -import InfraEnvironments from '../InfraEnvironments' - -jest.mock('@openshift-console/dynamic-plugin-sdk', () => ({ - ...jest.requireActual('@openshift-console/dynamic-plugin-sdk'), // use actual for all non-hook parts - useK8sWatchResource: jest.fn(), -})) -;(dynamicPluginSdk.useK8sWatchResource as jest.Mock).mockReturnValue([null as any, true, null]) - -const mockInfraEnvironments: InfraEnvK8sResource[] = [mockInfraEnv1] - -// This will be changed after MGMT-7255 -const mockInfraEnvRegeneratedISO = cloneDeep(mockInfraEnv1) -set(mockInfraEnvRegeneratedISO, 'status.createdTime', '2021-11-10T14:03:16Z') - -const mockNMStateConfigInfraEnv = cloneDeep(mockNMStateConfig) -mockNMStateConfigInfraEnv.metadata.name = infraEnvName -mockNMStateConfigInfraEnv.metadata.namespace = infraEnvName - -jest.mock('react-router-dom-v5-compat', () => { - const originalModule = jest.requireActual('react-router-dom-v5-compat') - return { - __esModule: true, - ...originalModule, - useParams: () => { - return { name: infraEnvName, namespace: infraEnvName } - }, - useNavigate: () => jest.fn(), - } -}) - -const Component = () => { - return ( - { - snapshot.set(infraEnvironmentsState, mockInfraEnvironments) - snapshot.set(nmStateConfigsState, [mockNMStateConfigInfraEnv]) - }} - > - - - } /> - - - - ) -} - -describe('Infrastructure Environment Details page', () => { - beforeEach(() => nockIgnoreApiPaths()) - test('can render', async () => { - const initialNocks = [nockGet(mockPullSecret as IResource)] - const generateNocks = [ - nockPatch( - { - apiVersion: 'agent-install.openshift.io/v1beta1', - kind: 'infraenvs', - metadata: { - namespace: 'infra-env-name', - name: 'infra-env-name', - }, - } as IResource, - [ - { - op: 'add', - path: '/spec/imageType', - value: 'minimal-iso', - }, - ] - ), - nockGet({ - apiVersion: 'agent-install.openshift.io/v1beta1', - kind: 'infraenvs', - metadata: { - namespace: 'infra-env-name', - name: 'infra-env-name', - }, - }), - ] - - render() - - await waitForText('ai:Infrastructure environment details') - await waitForNocks(initialNocks) - - // The Overview tab - await waitForText('ai:Name') - - // Open discovery ISO dialog - await clickHostAction('ai:With Discovery ISO') - - // // Discovery ISO download state - await waitForText('ai:Generate Discovery ISO') - await clickByText('ai:Generate Discovery ISO') - - await waitForNocks(generateNocks) - await waitForText('ai:Download Discovery ISO') - - await clickByText('ai:Close') - await waitForNotText('ai:Download Discovery ISO') - - // The Hosts tab - await clickByText('Hosts') - await waitForText('ai:Hosts may take a few minutes to appear here after booting.') - }) -}) diff --git a/frontend/src/routes/Infrastructure/InfraEnvironments/Details/InfraEnvironmentDetailsPage.tsx b/frontend/src/routes/Infrastructure/InfraEnvironments/Details/InfraEnvironmentDetailsPage.tsx deleted file mode 100644 index 1f60a5e0a52..00000000000 --- a/frontend/src/routes/Infrastructure/InfraEnvironments/Details/InfraEnvironmentDetailsPage.tsx +++ /dev/null @@ -1,166 +0,0 @@ -/* Copyright Contributors to the Open Cluster Management project */ -import { Page } from '@patternfly/react-core' -import { AcmButton, AcmPage, AcmPageHeader, AcmSecondaryNav, AcmSecondaryNavItem } from '../../../../ui-components' -import { isMatch } from 'lodash' -import { - AgentClusterInstallK8sResource, - InfraEnvHostsTabAgentsWarning, - INFRAENV_AGENTINSTALL_LABEL_KEY, - getAgentsHostsNames, - AddHostDropdown, - InfraEnvK8sResource, - AgentK8sResource, - BareMetalHostK8sResource, - NMStateK8sResource, -} from '@openshift-assisted/ui-lib/cim' -import { Fragment, Suspense, useMemo } from 'react' -import { - Link, - useLocation, - useNavigate, - useParams, - PathParam, - generatePath, - useOutletContext, - Outlet, -} from 'react-router-dom-v5-compat' -import { useRecoilValue, useSharedAtoms } from '../../../../shared-recoil' -import { ErrorPage } from '../../../../components/ErrorPage' -import { useTranslation } from '../../../../lib/acm-i18next' -import { NavigationPath } from '../../../../NavigationPath' -import { ResourceError, ResourceErrorCode } from '../../../../resources/utils' -import { - getOnCreateBMH, - getOnSaveISOParams, - importYaml, - useInfraEnv, - useProvisioningConfiguration, -} from '../../Clusters/ManagedClusters/CreateCluster/components/assisted-installer/utils' -import { getInfraEnvNMStates } from '../utils' -import { DOC_VERSION } from '../../../../lib/doc-util' - -type InfraEnvironmentDetailsContext = { - agentClusterInstalls: AgentClusterInstallK8sResource[] - infraEnv: InfraEnvK8sResource - infraAgents: AgentK8sResource[] - bareMetalHosts: BareMetalHostK8sResource[] - infraNMStates: NMStateK8sResource[] -} - -const InfraEnvironmentDetailsPage: React.FC = () => { - const { t } = useTranslation() - const navigate = useNavigate() - const location = useLocation() - const { name = '', namespace = '' } = useParams>() - - const { agentClusterInstallsState, agentsState, bareMetalHostsState, nmStateConfigsState } = useSharedAtoms() - const agentClusterInstalls = useRecoilValue(agentClusterInstallsState) - const agents = useRecoilValue(agentsState) - const bareMetalHosts = useRecoilValue(bareMetalHostsState) - const nmStateConfigs = useRecoilValue(nmStateConfigsState) - const infraEnv = useInfraEnv({ name, namespace }) - - const infraNMStates = useMemo(() => getInfraEnvNMStates(nmStateConfigs, infraEnv), [nmStateConfigs, infraEnv]) - - const infraAgents = useMemo( - () => - agents.filter( - (a) => - a.metadata?.namespace === infraEnv?.metadata?.namespace && - isMatch(a.metadata?.labels || {}, infraEnv?.status?.agentLabelSelector?.matchLabels || {}) - ), - [agents, infraEnv] - ) - - const infraBMHs = useMemo( - () => - bareMetalHosts.filter( - (bmh) => - bmh.metadata?.namespace === infraEnv?.metadata?.namespace && - bmh.metadata?.labels?.[INFRAENV_AGENTINSTALL_LABEL_KEY] === infraEnv?.metadata?.name - ), - [bareMetalHosts, infraEnv?.metadata?.namespace, infraEnv?.metadata?.name] - ) - - const infraEnvDetailsContext = useMemo( - () => ({ - agentClusterInstalls, - infraEnv, - infraAgents, - bareMetalHosts: infraBMHs, - infraNMStates, - }), - [agentClusterInstalls, infraAgents, infraBMHs, infraEnv, infraNMStates] - ) - - const usedHostnames = useMemo(() => getAgentsHostsNames(infraAgents, infraBMHs), [infraAgents, infraBMHs]) - const provisioningConfigResult = useProvisioningConfiguration() - if (!infraEnv) { - return ( - - navigate(NavigationPath.infraEnvironments)}> - {t('button.backToInfraEnvs')} - - } - /> - - ) - } - - const overviewPath = generatePath(NavigationPath.infraEnvironmentOverview, { name, namespace }) - const hostsPath = generatePath(NavigationPath.infraEnvironmentHosts, { name, namespace }) - - return ( - <> - - - {t('tab.details')} - - - - {t('tab.hosts')} - - - - - } - actions={ - - } - /> - } - > - }> - - - - - ) -} - -export function useInfraEnvironmentDetailsContext() { - return useOutletContext() -} - -export default InfraEnvironmentDetailsPage diff --git a/frontend/src/routes/Infrastructure/InfraEnvironments/InfraEnvForm.css b/frontend/src/routes/Infrastructure/InfraEnvironments/InfraEnvForm.css deleted file mode 100644 index e5d2e1c790e..00000000000 --- a/frontend/src/routes/Infrastructure/InfraEnvironments/InfraEnvForm.css +++ /dev/null @@ -1,15 +0,0 @@ -.temptifly .creation-view-controls-custom .pf-v5-c-input-group { - max-width: unset; -} - -.temptifly.showEditor .infra-env-form > .pf-v5-l-grid__item { - --pf-v5-l-grid__item--GridColumnEnd: span 12; -} - -.temptifly .infra-env-form .pf-v5-c-form__group-label { - padding: 0 0 var(--pf-v5-c-form__group-label--PaddingBottom) 0 !important; -} - -.infra-env-form__section { - padding: 0 0 var(--pf-v5-c-page__main-section--PaddingBottom) 0 !important; -} diff --git a/frontend/src/routes/Infrastructure/InfraEnvironments/InfraEnvForm.test.tsx b/frontend/src/routes/Infrastructure/InfraEnvironments/InfraEnvForm.test.tsx deleted file mode 100644 index b964027c0e8..00000000000 --- a/frontend/src/routes/Infrastructure/InfraEnvironments/InfraEnvForm.test.tsx +++ /dev/null @@ -1,84 +0,0 @@ -/* Copyright Contributors to the Open Cluster Management project */ -import { render } from '@testing-library/react' -import { MemoryRouter, Route, Routes } from 'react-router-dom-v5-compat' -import { RecoilRoot } from 'recoil' - -import { infraEnvironmentsState } from '../../../atoms' -import { nockIgnoreApiPaths, nockIgnoreRBAC } from '../../../lib/nock-util' -import { waitForText } from '../../../lib/test-util' -import { NavigationPath } from '../../../NavigationPath' -import InfraEnvForm from './InfraEnvForm' -import { InfraEnvK8sResource } from '@openshift-assisted/ui-lib/cim' - -export const infraEnvName = 'infra-env-name' - -export const mockInfraEnv1: InfraEnvK8sResource = { - apiVersion: 'agent-install.openshift.io/v1beta1', - kind: 'InfraEnv', - metadata: { - labels: { - 'agentclusterinstalls.extensions.hive.openshift.io/location': 'brno', - networkType: 'dhcp', - }, - name: infraEnvName, - namespace: infraEnvName, - }, - spec: { - agentLabels: { - 'agentclusterinstalls.extensions.hive.openshift.io/location': 'brno', - }, - pullSecretRef: { - name: `pullsecret-${infraEnvName}`, - }, - }, - status: { - agentLabelSelector: { - matchLabels: { - 'infraenvs.agent-install.openshift.io': infraEnvName, - }, - }, - conditions: [ - { - lastTransitionTime: '2021-10-04T11:26:37Z', - message: 'Image has been created', - reason: 'ImageCreated', - status: 'True', - type: 'ImageCreated', - }, - ], - createdTime: '2021-11-10T13:00:00Z', - isoDownloadURL: 'https://my.funny.download.url', - }, -} - -const mockInfraEnvironments: InfraEnvK8sResource[] = [mockInfraEnv1] - -const Component = () => { - return ( - { - snapshot.set(infraEnvironmentsState, mockInfraEnvironments) - }} - > - - - {}} />} - /> - - - - ) -} - -describe('Infrastructure Environments page', () => { - beforeEach(() => { - nockIgnoreRBAC() - nockIgnoreApiPaths() - }) - test('can render', async () => { - render() - await waitForText('ai:Name', true) - }) -}) diff --git a/frontend/src/routes/Infrastructure/InfraEnvironments/InfraEnvForm.tsx b/frontend/src/routes/Infrastructure/InfraEnvironments/InfraEnvForm.tsx deleted file mode 100644 index ef3107a5355..00000000000 --- a/frontend/src/routes/Infrastructure/InfraEnvironments/InfraEnvForm.tsx +++ /dev/null @@ -1,225 +0,0 @@ -/* Copyright Contributors to the Open Cluster Management project */ -import { - Card, - CardBody, - CardTitle, - FormGroup, - Grid, - GridItem, - Modal, - ModalVariant, - PageSection, - SelectOption, - Split, - SplitItem, - Stack, - StackItem, -} from '@patternfly/react-core' -import { AcmSelectBase, SelectVariant } from '../../../components/AcmSelectBase' -import { - InfraEnvFormPage, - EnvironmentStepFormValues, - AgentServiceConfigK8sResource, -} from '@openshift-assisted/ui-lib/cim' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { FormikProps } from 'formik' - -import { useTranslation } from '../../../lib/acm-i18next' -import MainIcon from '../../../logos/OnPremiseBannerIcon.svg' -import { useSharedAtoms, useRecoilValue, useSharedSelectors } from '../../../shared-recoil' - -import './InfraEnvForm.css' -import { CredentialsForm } from '../../Credentials/CredentialsForm' -import { Provider } from '../../../ui-components' -import { useProjects } from '../../../hooks/useProjects' -import { CreateCredentialModal } from '../../../components/CreateCredentialModal' -import { DOC_VERSION } from '../../../lib/doc-util' - -// where to put Create/Cancel buttons -export const Portals = Object.freeze({ - editBtn: 'edit-button-portal-id', - createBtn: 'create-button-portal-id', - cancelBtn: 'cancel-button-portal-id', -}) - -const portals = ( - - - -
- - -
- - - -) - -const getLabels = (values: EnvironmentStepFormValues) => - values.labels.reduce( - (acc, curr) => { - const label = curr.split('=') - acc[label[0]] = label[1] - return acc - }, - {} as Record - ) - -type InfraEnvFormProps = { - control?: any - handleChange?: any -} - -const InfraEnvForm: React.FC = ({ control, handleChange }) => { - const { t } = useTranslation() - - const [isCredentialsModalOpen, setCredentialsModalOpen] = useState(false) - const [credentialsUID, setCredentialsUID] = useState() - const { providerConnectionsValue } = useSharedSelectors() - const allProviderConnections = useRecoilValue(providerConnectionsValue) - const { projects } = useProjects() - const { infraEnvironmentsState, agentServiceConfigsState } = useSharedAtoms() - const infraEnvironments = useRecoilValue(infraEnvironmentsState) - const agentServiceConfigs = useRecoilValue(agentServiceConfigsState) - const osImages = (agentServiceConfigs?.[0] as AgentServiceConfigK8sResource)?.spec.osImages || [] - - const formRef = useRef>(null) - - const providerConnections = allProviderConnections.filter((p) => { - const providerType = p.metadata?.labels?.['cluster.open-cluster-management.io/type'] - if (providerType) { - return [Provider.hostinventory, Provider.nutanix].includes(providerType as Provider) - } - return false - }) - - const onValuesChanged = useCallback((values: EnvironmentStepFormValues) => { - control.active = values - if (values.labels) { - control.active = { - ...control.active, - labels: getLabels(values), - } - } - if (values.pullSecret) { - control.active = { - ...control.active, - pullSecret: btoa(values.pullSecret), - } - } - if (values.enableNtpSources) { - control.active = { - ...control.active, - additionalNtpSources: values.additionalNtpSources - .split(',') - .map((s) => s.trim()) - .filter(Boolean), - } - } - handleChange(control) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) - - useEffect(() => { - control.validate = () => { - return formRef?.current?.submitForm().then(() => { - return formRef?.current?.errors - }) - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) - - const infraEnvNames = useMemo(() => infraEnvironments.map((ie) => ie.metadata?.name!), [infraEnvironments]) - const currentConnection = providerConnections.find((p) => p.metadata.uid === credentialsUID) - return ( - <> - - - - {/*@ts-expect-error @openshift-assisted/ui-lib needs React 18 updates*/} - - - { - setCredentialsUID(v as string) - }} - selections={credentialsUID} - footer={ - setCredentialsModalOpen(!isCredentialsModalOpen)} /> - } - > - {providerConnections.map((p) => ( - - {p.metadata.name} - - ))} - - - - - - - - - - - - - - {t('Next steps: Adding hosts')} - - - - {t( - 'After your infrastructure environment is successfully created, open the details view and click the "Add hosts" button.' - )} - - - {t( - 'Adding hosts allows cluster creators to pull any available hosts from the infrastructure environment.' - )} - - - - - - - - - - {isCredentialsModalOpen && ( - setCredentialsModalOpen(false)} - hasNoBodyWrapper - > - setCredentialsModalOpen(!isCredentialsModalOpen)} - hideYaml - newCredentialCallback={(r) => setCredentialsUID(r.metadata?.uid)} - /> - - )} - {portals} - - ) -} - -export default InfraEnvForm diff --git a/frontend/src/routes/Infrastructure/InfraEnvironments/InfraEnvironments.tsx b/frontend/src/routes/Infrastructure/InfraEnvironments/InfraEnvironments.tsx deleted file mode 100644 index 3546a3f245f..00000000000 --- a/frontend/src/routes/Infrastructure/InfraEnvironments/InfraEnvironments.tsx +++ /dev/null @@ -1,33 +0,0 @@ -/* Copyright Contributors to the Open Cluster Management project */ -import { Navigate, Route, Routes } from 'react-router-dom-v5-compat' -import CreateInfraEnv from './CreateInfraEnv' -import InfraEnvironmentDetailsPage from './Details/InfraEnvironmentDetailsPage' -import InfraEnvironmentsPage from './InfraEnvironmentsPage' -import { MatchType, NavigationPath, SubRoutesRedirect, createRoutePathFunction } from '../../../NavigationPath' -import DetailsTab from './Details/DetailsTab' -import HostsTab from './Details/HostsTab' - -const infraEnvironmentsChildPath = createRoutePathFunction(NavigationPath.infraEnvironments) - -export default function InfraEnvironments() { - return ( - - }> - } /> - } /> - - - } - /> - } /> - } /> - } /> - - ) -} diff --git a/frontend/src/routes/Infrastructure/InfraEnvironments/InfraEnvironmentsPage.test.tsx b/frontend/src/routes/Infrastructure/InfraEnvironments/InfraEnvironmentsPage.test.tsx index 0dab31a3a85..775f66a445d 100644 --- a/frontend/src/routes/Infrastructure/InfraEnvironments/InfraEnvironmentsPage.test.tsx +++ b/frontend/src/routes/Infrastructure/InfraEnvironments/InfraEnvironmentsPage.test.tsx @@ -8,7 +8,6 @@ import { RecoilRoot } from 'recoil' import { infraEnvironmentsState } from '../../../atoms' import { nockIgnoreApiPaths, nockIgnoreRBAC } from '../../../lib/nock-util' import { getCSVDownloadLink, getCSVExportSpies, waitForTestId, waitForText } from '../../../lib/test-util' -import { NavigationPath } from '../../../NavigationPath' import InfraEnvironmentsPage, { getFirstAgentServiceConfig, getInfraEnvsOfMatchingPullSecret, @@ -61,9 +60,12 @@ const Component = () => { snapshot.set(infraEnvironmentsState, mockInfraEnvironments) }} > - + - } /> + } + /> diff --git a/frontend/src/routes/Infrastructure/InfraEnvironments/InfraEnvironmentsPage.tsx b/frontend/src/routes/Infrastructure/InfraEnvironments/InfraEnvironmentsPage.tsx index 1f49368ae2c..a6d09cf36af 100644 --- a/frontend/src/routes/Infrastructure/InfraEnvironments/InfraEnvironmentsPage.tsx +++ b/frontend/src/routes/Infrastructure/InfraEnvironments/InfraEnvironmentsPage.tsx @@ -34,19 +34,18 @@ import { PatchResourceFuncType, InfrastructureK8sResource, } from '@openshift-assisted/ui-lib/cim' -import { useState, useEffect, useMemo } from 'react' -import { Link, generatePath, useNavigate } from 'react-router-dom-v5-compat' +import React, { useState, useEffect, useMemo } from 'react' +import { Link, useNavigate } from 'react-router-dom-v5-compat' import { BulkActionModal, BulkActionModalProps } from '../../../components/BulkActionModal' import { RbacDropdown } from '../../../components/Rbac' import { useTranslation } from '../../../lib/acm-i18next' import { deleteResources } from '../../../lib/delete-resources' import { DOC_LINKS, OCP_DOC, ViewDocumentationLink } from '../../../lib/doc-util' import { canUser, rbacDelete } from '../../../lib/rbac-util' -import { NavigationPath } from '../../../NavigationPath' import { getDateTimeCell } from '../helpers/table-row-helpers' import { useSharedAtoms, useRecoilValue } from '../../../shared-recoil' import { IResource } from '../../../resources/resource' -import { K8sResourceCommon } from '@openshift-console/dynamic-plugin-sdk' +import { K8sResourceCommon, useActiveNamespace } from '@openshift-console/dynamic-plugin-sdk' import { ResourceError, createResource, @@ -166,11 +165,27 @@ const k8sPrimitives: { patchResource: (...params) => patchResource(...params).promise, } -const InfraEnvironmentsPage: React.FC = () => { - const { agentsState, infraEnvironmentsState, infrastructuresState, agentServiceConfigsState, storageClassState } = - useSharedAtoms() +const usePageResources = (): [InfraEnvK8sResource[], AgentK8sResource[]] => { + const [activeNs] = useActiveNamespace() + const { agentsState, infraEnvironmentsState } = useSharedAtoms() const infraEnvs = useRecoilValue(infraEnvironmentsState) const agents = useRecoilValue(agentsState) + + return React.useMemo(() => { + if (activeNs === '#ALL_NS#') { + return [infraEnvs, agents] + } + + return [ + infraEnvs.filter((ie) => ie.metadata?.namespace === activeNs), + agents.filter((agent) => agent.metadata?.namespace === activeNs), + ] + }, [activeNs, agents, infraEnvs]) +} + +const InfraEnvironmentsPage: React.FC = () => { + const { infrastructuresState, agentServiceConfigsState, storageClassState } = useSharedAtoms() + const [infraEnvs, agents] = usePageResources() const infrastructures = useRecoilValue(infrastructuresState) const agentServiceConfigs = useRecoilValue(agentServiceConfigsState) const storageClasses = useRecoilValue(storageClassState) @@ -274,14 +289,16 @@ type InfraEnvsTableProps = { isStorage: boolean } +const getCreateLink = (ns: string) => + `/k8s/ns/${ns === '#ALL_NS#' ? 'default' : ns}/agent-install.openshift.io~v1beta1~InfraEnv/~new` + +const getDetailsLink = (infraEnv: InfraEnvK8sResource) => + `/k8s/ns/${infraEnv.metadata?.namespace}/agent-install.openshift.io~v1beta1~InfraEnv/${infraEnv.metadata?.name}` + const InfraEnvsTable: React.FC = ({ infraEnvs, agents, agentServiceConfig, isStorage }) => { + const [ns] = useActiveNamespace() const { t } = useTranslation() const navigate = useNavigate() - const getDetailsLink = (infraEnv: InfraEnvK8sResource) => - generatePath(NavigationPath.infraEnvironmentDetails, { - namespace: infraEnv.metadata?.namespace!, - name: infraEnv.metadata?.name!, - }) const { clusterVersionState } = useSharedAtoms() const clusterVersions = useRecoilValue(clusterVersionState) @@ -636,7 +653,7 @@ const InfraEnvsTable: React.FC = ({ infraEnvs, agents, agen { id: 'createInfraEnv', title: t('infraEnv.bulkAction.createInfraEnv'), - click: () => navigate(NavigationPath.createInfraEnv), + click: () => navigate(getCreateLink(ns)), variant: ButtonVariant.primary, }, ]} @@ -660,7 +677,7 @@ const InfraEnvsTable: React.FC = ({ infraEnvs, agents, agen { - navigate(NavigationPath.createInfraEnv) + navigate(getCreateLink(ns)) }} isDisabled={!isCIMWorking} tooltip={ diff --git a/frontend/src/routes/Infrastructure/InfraEnvironments/InfraEnvironmentsPlugin.tsx b/frontend/src/routes/Infrastructure/InfraEnvironments/InfraEnvironmentsPlugin.tsx index a6288ade9d4..1380156d175 100644 --- a/frontend/src/routes/Infrastructure/InfraEnvironments/InfraEnvironmentsPlugin.tsx +++ b/frontend/src/routes/Infrastructure/InfraEnvironments/InfraEnvironmentsPlugin.tsx @@ -2,14 +2,14 @@ import { ACMNotReadyWarning } from '../../../components/ACMNotReadyWarning' import { LoadPluginData } from '../../../components/LoadPluginData' import { PluginContextProvider } from '../../../components/PluginContextProvider' -import InfraEnvironments from './InfraEnvironments' +import InfraEnvironmentsPage from './InfraEnvironmentsPage' export default function InfraEnvironmentsPlugin() { return ( - + diff --git a/frontend/src/routes/Infrastructure/InfraEnvironments/infraenv-template.hbs b/frontend/src/routes/Infrastructure/InfraEnvironments/infraenv-template.hbs deleted file mode 100644 index c8f85749524..00000000000 --- a/frontend/src/routes/Infrastructure/InfraEnvironments/infraenv-template.hbs +++ /dev/null @@ -1,73 +0,0 @@ -kind: Secret -apiVersion: v1 -metadata: - name: pullsecret-{{{ai.name}}} - namespace: {{{ai.name}}} -data: - '.dockerconfigjson': '{{{ai.pullSecret}}}' -type: 'kubernetes.io/dockerconfigjson' ---- -apiVersion: agent-install.openshift.io/v1beta1 -kind: InfraEnv -metadata: - name: {{{ai.name}}} - namespace: {{{ai.name}}} - labels: - agentclusterinstalls.extensions.hive.openshift.io/location: {{{ai.location}}} - networkType: {{{ai.networkType}}} -spec: - agentLabels: - 'agentclusterinstalls.extensions.hive.openshift.io/location': {{{ai.location}}} - {{#each ai.labels}} - {{@key}}: {{this}} - {{/each}} - pullSecretRef: - name: pullsecret-{{{ai.name}}} - sshAuthorizedKey: {{{ai.sshPublicKey}}} - {{#if (checkNtpSources ai.enableNtpSources ai.additionalNtpSources)}} - additionalNTPSources: - {{#each ai.additionalNtpSources}} - - {{this}} - {{/each}} - {{/if}} - nmStateConfigLabelSelector: - matchLabels: - infraenvs.agent-install.openshift.io: {{ ai.name }} - {{#if ai.enableProxy}} - proxy: - {{#if ai.httpProxy}} - httpProxy: {{{ ai.httpProxy }}} - {{/if}} - {{#if ai.httpsProxy}} - httpsProxy: {{{ ai.httpsProxy }}} - {{/if}} - {{#if ai.noProxy}} - noProxy: '{{{ ai.noProxy }}}' - {{/if}} - {{/if}} - {{#if ai.cpuArchitecture}} - cpuArchitecture: {{{ai.cpuArchitecture}}} - {{/if}} - {{#if ai.osImageVersion}} - osImageVersion: '{{{ ai.osImageVersion }}}' - {{/if}} -status: - agentLabelSelector: - matchLabels: - 'agentclusterinstalls.extensions.hive.openshift.io/location': {{{ai.location}}} - {{#each ai.labels}} - {{@key}}: {{this}} - {{/each}} ---- -kind: Role -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: capi-provider-role - namespace: {{{ai.name}}} -rules: - - verbs: - - '*' - apiGroups: - - agent-install.openshift.io - resources: - - agents diff --git a/frontend/src/routes/Infrastructure/InfraEnvironments/utils.ts b/frontend/src/routes/Infrastructure/InfraEnvironments/utils.ts deleted file mode 100644 index aa384e6c947..00000000000 --- a/frontend/src/routes/Infrastructure/InfraEnvironments/utils.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* Copyright Contributors to the Open Cluster Management project */ -import { InfraEnvK8sResource, InfrastructureK8sResource, NMStateK8sResource } from '@openshift-assisted/ui-lib/cim' -import { isMatch } from 'lodash' - -export const isBMPlatform = (infrastructure?: InfrastructureK8sResource) => - ['BareMetal', 'None', 'OpenStack', 'VSphere'].includes(infrastructure?.status?.platform || '') - -export const getInfraEnvNMStates = (nmStateConfigs: NMStateK8sResource[], infraEnv?: InfraEnvK8sResource) => - nmStateConfigs.filter((nmStateConfig) => { - if (!Object.keys(infraEnv?.spec?.nmStateConfigLabelSelector?.matchLabels || {}).length) return false - return isMatch(nmStateConfig.metadata?.labels || {}, infraEnv?.spec?.nmStateConfigLabelSelector?.matchLabels || {}) - })