-
Notifications
You must be signed in to change notification settings - Fork 55
feature: add EKS create cluster #2631
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from 6 commits
7f7ce6c
c33683c
7b854ec
183aab0
e8b3919
2872262
628c25e
82e0342
eedce6f
ff2103c
d4c3bb1
f54785d
126d069
5272ac4
861cdd6
85ae37e
7f420c4
e8b73db
34361a0
9b15d0f
6895d52
69e02df
009161a
7a2d1f8
f3b52ae
dc27867
2cc2f8a
0377d54
5481073
a6390d2
6556258
95a6174
9a4027d
e70370a
473d780
26dd52f
dd4e830
e43f596
7f154a9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import { | ||
Button, | ||
ButtonComponentType, | ||
ButtonStyleType, | ||
ButtonVariantType, | ||
ComponentSizeType, | ||
DEFAULT_ROUTE_PROMPT_MESSAGE, | ||
Drawer, | ||
stopPropagation, | ||
} from '@devtron-labs/devtron-fe-common-lib' | ||
import { Prompt, Redirect, useHistory, useParams } from 'react-router-dom' | ||
import { useState } from 'react' | ||
import { ReactComponent as ICClose } from '@Icons/ic-close.svg' | ||
import { URLS } from '@Config/routes' | ||
import { importComponentFromFELibrary } from '@Components/common' | ||
|
||
import { CreateClusterParams, CreateClusterTypeEnum } from './types' | ||
import Sidebar from './Sidebar' | ||
import FooterComponent from './FooterComponent' | ||
|
||
const CreateClusterForm = importComponentFromFELibrary('CreateClusterForm', null, 'function') | ||
|
||
const CreateCluster = () => { | ||
const { type } = useParams<CreateClusterParams>() | ||
|
||
const [apiCallInProgress, setApiCallInProgress] = useState(false) | ||
|
||
const { push } = useHistory() | ||
|
||
const handleRedirectToClusterList = () => { | ||
push(URLS.GLOBAL_CONFIG_CLUSTER) | ||
} | ||
|
||
const renderContent = () => { | ||
switch (type) { | ||
case CreateClusterTypeEnum.CONNECT_CLUSTER: | ||
return 'connect cluster' | ||
case CreateClusterTypeEnum.CREATE_EKS_CLUSTER: | ||
return ( | ||
<CreateClusterForm | ||
apiCallInProgress={apiCallInProgress} | ||
setApiCallInProgress={setApiCallInProgress} | ||
handleModalClose={handleRedirectToClusterList} | ||
FooterComponent={FooterComponent} | ||
/> | ||
) | ||
case CreateClusterTypeEnum.ADD_ISOLATED_CLUSTER: | ||
return 'create isolated cluster' | ||
default: | ||
return <Redirect to={URLS.GLOBAL_CONFIG_CLUSTER} /> | ||
} | ||
} | ||
|
||
return ( | ||
<Drawer | ||
position="right" | ||
width="1024px" | ||
onEscape={handleRedirectToClusterList} | ||
onClose={handleRedirectToClusterList} | ||
> | ||
<dialog | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should not use dialog here, should be catered in Drawer component later |
||
className="bg__primary h-100 cn-9 w-100 flexbox-col dc__overflow-hidden p-0" | ||
onClick={stopPropagation} | ||
> | ||
<header className="px-20 py-12 lh-24 flexbox dc__content-space dc__align-items-center dc__border-bottom"> | ||
<span className="fs-16 fw-6 dc__first-letter-capitalize">New Cluster</span> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: Can be a h tag |
||
|
||
<Button | ||
icon={<ICClose />} | ||
dataTestId="close-create-cluster-modal-button" | ||
component={ButtonComponentType.button} | ||
style={ButtonStyleType.negativeGrey} | ||
size={ComponentSizeType.xs} | ||
variant={ButtonVariantType.borderLess} | ||
ariaLabel="Close new cluster drawer" | ||
showTooltip={apiCallInProgress} | ||
tooltipProps={{ | ||
content: DEFAULT_ROUTE_PROMPT_MESSAGE, | ||
}} | ||
disabled={apiCallInProgress} | ||
onClick={handleRedirectToClusterList} | ||
showAriaLabelInTippy={false} | ||
/> | ||
</header> | ||
|
||
<div className="flexbox flex-grow-1 dc__overflow-hidden"> | ||
<Sidebar /> | ||
|
||
<div className="bg__tertiary flex-grow-1 flexbox-col dc__overflow-auto p-20 dc__gap-16"> | ||
{renderContent()} | ||
</div> | ||
</div> | ||
|
||
<Prompt when={apiCallInProgress} message={DEFAULT_ROUTE_PROMPT_MESSAGE} /> | ||
</dialog> | ||
</Drawer> | ||
) | ||
} | ||
|
||
export default CreateCluster |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { Button, ButtonVariantType, NewClusterFormFooterProps } from '@devtron-labs/devtron-fe-common-lib' | ||
Check failure on line 1 in src/Pages/GlobalConfigurations/ClustersAndEnvironments/CreateCluster/FooterComponent.tsx
|
||
import { PropsWithChildren } from 'react' | ||
|
||
const FooterComponent = ({ | ||
apiCallInProgress, | ||
handleModalClose, | ||
children, | ||
}: PropsWithChildren<NewClusterFormFooterProps>) => ( | ||
<footer className="dc__position-abs dc__bottom-0 dc__left-0 w-100 dc__zi-1 bg__primary flexbox dc__content-end dc__border-top-n1 px-20 py-16 dc__gap-12 dc__no-shrink"> | ||
<Button | ||
dataTestId="cancel-create-cluster-button" | ||
onClick={handleModalClose} | ||
disabled={apiCallInProgress} | ||
text="Cancel" | ||
variant={ButtonVariantType.secondary} | ||
/> | ||
|
||
{children} | ||
</footer> | ||
) | ||
|
||
export default FooterComponent |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/* | ||
* Copyright (c) 2024. Devtron Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
import { Icon, IconName, ModalSidebarPanel } from '@devtron-labs/devtron-fe-common-lib' | ||
import { DOCUMENTATION } from '@Config/constants' | ||
import { generatePath, NavLink, useParams } from 'react-router-dom' | ||
import { URLS } from '@Config/routes' | ||
|
||
import { CreateClusterParams } from './types' | ||
import { SIDEBAR_CONFIG } from './constants' | ||
|
||
const Sidebar = () => { | ||
const { type } = useParams<CreateClusterParams>() | ||
|
||
const selectedSidebarElement = SIDEBAR_CONFIG[type] | ||
|
||
return ( | ||
<div className="w-250 p-20 flexbox-col dc__gap-24 dc__no-shrink dc__overflow-auto"> | ||
<div className="flexbox-col"> | ||
{Object.entries(SIDEBAR_CONFIG).map(([key, { title, iconName }]) => { | ||
const isSelected = type.toLowerCase() === key.toLowerCase() | ||
|
||
return ( | ||
<NavLink | ||
className={`dc__transparent flex left dc__gap-8 py-6 px-8 br-4 ${isSelected ? 'bcb-1' : 'dc__hover-n50'}`} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing key |
||
to={generatePath(URLS.GLOBAL_CONFIG_CREATE_CLUSTER, { type: key })} | ||
> | ||
<span className="dc__fill-available-space dc__no-shrink icon-dim-16"> | ||
<Icon name={iconName as IconName} color={isSelected ? 'B500' : 'N600'} /> | ||
</span> | ||
|
||
<span className={`fs-13 lh-20 dc__truncate ${isSelected ? 'cb-5 fw-6' : 'cn-9'}`}> | ||
{title} | ||
</span> | ||
</NavLink> | ||
) | ||
})} | ||
</div> | ||
|
||
<div className="divider__secondary--horizontal" /> | ||
|
||
<ModalSidebarPanel | ||
heading={selectedSidebarElement.documentationHeader ?? selectedSidebarElement.title} | ||
documentationLink={DOCUMENTATION.CLUSTER_AND_ENVIRONMENT} | ||
rootClassName="w-100 dc__no-background-imp" | ||
> | ||
<div className="flexbox-col dc__gap-24">{selectedSidebarElement.body}</div> | ||
</ModalSidebarPanel> | ||
</div> | ||
) | ||
} | ||
|
||
export default Sidebar |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { IconName } from '@devtron-labs/devtron-fe-common-lib' | ||
import { CreateClusterTypeEnum, SidebarConfigType } from './types' | ||
|
||
export const SIDEBAR_CONFIG: SidebarConfigType = { | ||
[CreateClusterTypeEnum.CONNECT_CLUSTER]: { | ||
title: 'Connect cluster', | ||
iconName: 'ic-ci-linked' as IconName, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can sync as to why we had to use as. |
||
body: ( | ||
<p className="m-0"> | ||
Connect an existing Kubernetes cluster to manage Kubernetes resources and deploy containerized | ||
applications using Devtron. | ||
</p> | ||
), | ||
}, | ||
[CreateClusterTypeEnum.CREATE_EKS_CLUSTER]: { | ||
title: 'Create EKS cluster', | ||
iconName: 'ic-cluster' as IconName, | ||
body: ( | ||
<> | ||
<p className="m-0">With Devtron, you can effortlessly create an Amazon EKS cluster.</p> | ||
<p className="m-0"> | ||
Amazon Elastic Kubernetes Service (Amazon EKS) is a fully managed Kubernetes service that enables | ||
you to run Kubernetes seamlessly in both AWS Cloud and on-premises data centers. | ||
</p> | ||
</> | ||
), | ||
isEnterprise: true, | ||
}, | ||
[CreateClusterTypeEnum.ADD_ISOLATED_CLUSTER]: { | ||
title: 'Add Isolated Cluster', | ||
iconName: 'ic-add' as IconName, | ||
documentationHeader: 'Isolated Cluster', | ||
body: ( | ||
<> | ||
<p className="m-0"> | ||
An isolated cluster in Devtron is an air-gapped Kubernetes cluster with restricted network access. | ||
</p> | ||
<p className="m-0"> | ||
Since Devtron does not have connectivity to these clusters, deployments are managed by packaging | ||
manifests and images for manual installation or retrieval from an OCI registry (if enabled). | ||
</p> | ||
</> | ||
), | ||
isEnterprise: true, | ||
}, | ||
} as const |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { default as CreateClusterDrawer } from './CreateCluster.component' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
export enum CreateClusterTypeEnum { | ||
CONNECT_CLUSTER = 'connect-cluster', | ||
CREATE_EKS_CLUSTER = 'create-eks-cluster', | ||
ADD_ISOLATED_CLUSTER = 'add-isolated-cluster', | ||
} | ||
|
||
export type SidebarConfigType = Record< | ||
CreateClusterTypeEnum, | ||
{ | ||
title: string | ||
iconName: string | ||
body: React.ReactElement | ||
documentationHeader?: string | ||
isEnterprise?: true | ||
} | ||
> | ||
|
||
export interface CreateClusterParams { | ||
type: CreateClusterTypeEnum | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,8 @@ import { | |
getUrlWithSearchParams, | ||
getK8sResourceListPayload, | ||
stringComparatorBySortOrder, | ||
Nodes, | ||
getNamespaceListMin, | ||
} from '@devtron-labs/devtron-fe-common-lib' | ||
import { RefObject } from 'react' | ||
import { Routes } from '../../config' | ||
|
@@ -77,6 +79,40 @@ export const getResourceData = async ({ | |
return parseNodeList(response) | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pls verify silver surfer once |
||
if (selectedResource.gvk.Kind.toLowerCase() === Nodes.Namespace.toLowerCase()) { | ||
const { result } = await getNamespaceListMin(clusterId) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should send abortController as well |
||
const [{ environments }] = result | ||
|
||
const response = await getK8sResourceList( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Its common in else block and here, can common out. |
||
getK8sResourceListPayload(clusterId, selectedNamespace.value.toLowerCase(), selectedResource, filters), | ||
abortControllerRef.current.signal, | ||
) | ||
|
||
const namespaceToEnvironmentMap = environments.reduce( | ||
(acc, { environmentName, namespace, environmentId }) => { | ||
if (environmentId === 0) { | ||
return acc | ||
} | ||
|
||
acc[namespace] = environmentName | ||
return acc | ||
}, | ||
{}, | ||
) | ||
|
||
return { | ||
...response, | ||
result: { | ||
...response.result, | ||
headers: [...response.result.headers, 'environment'], | ||
data: response.result.data.map((data) => ({ | ||
...data, | ||
environment: namespaceToEnvironmentMap[data.name as string], | ||
})), | ||
}, | ||
} | ||
} | ||
|
||
return await getK8sResourceList( | ||
getK8sResourceListPayload(clusterId, selectedNamespace.value.toLowerCase(), selectedResource, filters), | ||
abortControllerRef.current.signal, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to add truncation