Skip to content

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

Open
wants to merge 39 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
7f7ce6c
feat: add environment column in namespace list
Elessar1802 Apr 3, 2025
c33683c
Merge pull request #2624 from devtron-labs/feat/add-environment-ns-list
Elessar1802 Apr 3, 2025
7b854ec
feat: add cluster name to modal header
Elessar1802 Apr 4, 2025
183aab0
fix: add cluster button in cluster list
Elessar1802 Apr 4, 2025
e8b3919
feat: CreateCluster in ClustersAndEnvironments
Elessar1802 Apr 6, 2025
2872262
Merge branch 'feature/create-cluster' of github.com:devtron-labs/dash…
Elessar1802 Apr 7, 2025
628c25e
feat: add ClusterConfig in cluster overview & integrate create cluste…
Elessar1802 Apr 7, 2025
82e0342
feat: show installation clusters in cluster list
Elessar1802 Apr 8, 2025
eedce6f
Merge branch 'feat/edit-cluster' of https://github.com/devtron-labs/d…
arunjaindev Apr 8, 2025
ff2103c
feat: add support for category label filters in chart listing
arunjaindev Apr 8, 2025
d4c3bb1
feat: add RESOURCE_BROWSER_INSTALLATION_CLUSTER to RB router
Elessar1802 Apr 8, 2025
f54785d
Merge branch 'feat/edit-cluster' of https://github.com/devtron-labs/d…
arunjaindev Apr 8, 2025
126d069
feat: add cluster installation page
arunjaindev Apr 8, 2025
5272ac4
feat: incorporate connect cluster & isolated cluster
Elessar1802 Apr 8, 2025
861cdd6
Merge branch 'feat/edit-cluster' of https://github.com/devtron-labs/d…
arunjaindev Apr 8, 2025
85ae37e
chore(text): change connect cluster to new cluster in RB page header
Elessar1802 Apr 8, 2025
7f420c4
fix: show all installation clusters not found in cluster list
Elessar1802 Apr 9, 2025
e8b73db
feat: add page header on cluster installation status page
arunjaindev Apr 9, 2025
34361a0
feat: update filter empty state
arunjaindev Apr 9, 2025
9b15d0f
fix: redirect to installation status after cluster creation
Elessar1802 Apr 9, 2025
6895d52
Merge branch 'feat/chart-category-filters' of github.com:devtron-labs…
Elessar1802 Apr 9, 2025
69e02df
Merge branch 'main' of https://github.com/devtron-labs/dashboard into…
arunjaindev Apr 9, 2025
009161a
Merge branch 'feature/create-cluster' of github.com:devtron-labs/dash…
Elessar1802 Apr 9, 2025
7a2d1f8
Merge branch 'feat/edit-cluster' of github.com:devtron-labs/dashboard…
Elessar1802 Apr 9, 2025
f3b52ae
chore: update common-lib version
Elessar1802 Apr 9, 2025
dc27867
fix: polling in cluster overview
Elessar1802 Apr 9, 2025
2cc2f8a
chore: update common-lib version
Elessar1802 Apr 10, 2025
0377d54
Merge pull request #2635 from devtron-labs/feat/edit-cluster
Elessar1802 Apr 11, 2025
5481073
Merge branch 'feat/eks-demo' into feature/create-cluster
Elessar1802 Apr 11, 2025
a6390d2
feat: add enterprise feature dialog
arunjaindev Apr 11, 2025
6556258
Merge branch 'develop' of github.com:devtron-labs/dashboard into feat…
Elessar1802 Apr 16, 2025
95a6174
fix: review comments
Elessar1802 Apr 16, 2025
9a4027d
fix: review comment
Elessar1802 Apr 16, 2025
e70370a
fix: review comment
Elessar1802 Apr 16, 2025
473d780
refactor: cluster form & open create cluster drawer in RB
Elessar1802 Apr 22, 2025
26dd52f
fix(text|style): cluster form
Elessar1802 Apr 22, 2025
dd4e830
refactor: cluster overview & don't fail on capacity api fail
Elessar1802 Apr 22, 2025
e43f596
feat: add DeleteClusterConfirmationModal & use in RB page header
Elessar1802 Apr 24, 2025
7f154a9
fix: self review
Elessar1802 Apr 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export const ClusterEnvironmentDrawer = ({
reload,
hideClusterDrawer,
isVirtual,
clusterName,
}: ClusterEnvironmentDrawerProps) => {
// STATES
// Manages the loading state for create and update actions
Expand Down Expand Up @@ -400,7 +401,9 @@ export const ClusterEnvironmentDrawer = ({
<Drawer position="right" width="800px" onEscape={hideClusterDrawer} onClose={hideClusterDrawer}>
<div className="h-100 bg__primary flexbox-col" onClick={stopPropagation}>
<div className="flexbox dc__align-items-center dc__content-space dc__border-bottom bg__primary py-12 px-20">
<h3 className="m-0 fs-16 fw-6 lh-1-43">{id ? 'Edit Environment' : 'Add Environment'}</h3>
<h3 className="m-0 fs-16 fw-6 lh-1-43">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to add truncation

{id ? 'Edit Environment' : `Add Environment in '${clusterName}'`}
</h3>
<button
type="button"
aria-label="close-btn"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export interface ClusterEnvironmentDrawerProps extends ClusterEnvironmentDrawerF
reload: () => void
hideClusterDrawer: () => void
isVirtual: boolean
clusterName: string
}

export type GetClusterEnvironmentUpdatePayloadType = Pick<
Expand Down
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
Copy link
Member

Choose a reason for hiding this comment

The 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>
Copy link
Member

Choose a reason for hiding this comment

The 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

View workflow job for this annotation

GitHub Actions / ci

Module '"@devtron-labs/devtron-fe-common-lib"' has no exported member 'NewClusterFormFooterProps'.

Check failure on line 1 in src/Pages/GlobalConfigurations/ClustersAndEnvironments/CreateCluster/FooterComponent.tsx

View workflow job for this annotation

GitHub Actions / ci

Module '"@devtron-labs/devtron-fe-common-lib"' has no exported member 'NewClusterFormFooterProps'.
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'}`}
Copy link
Member

Choose a reason for hiding this comment

The 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,
Copy link
Member

Choose a reason for hiding this comment

The 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
}
7 changes: 2 additions & 5 deletions src/assets/icons/ic-link.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 12 additions & 9 deletions src/components/ResourceBrowser/PageHeader.buttons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
*/

import React, { useState } from 'react'
import { NavLink } from 'react-router-dom'
import { Button, ComponentSizeType } from '@devtron-labs/devtron-fe-common-lib'
import { Button, ButtonComponentType, ComponentSizeType } from '@devtron-labs/devtron-fe-common-lib'
import { URLS } from '../../config'
import { CreateResource } from './ResourceList/CreateResource'
import { CreateResourceButtonType, CreateResourceType } from './Types'
Expand Down Expand Up @@ -52,13 +51,17 @@ export const renderCreateResourceButton = (clusterId: string, callback: CreateRe

export const AddClusterButton = (): JSX.Element => (
<div>
<NavLink
className="flex dc__no-decor cta small h-28 pl-8 pr-10 pt-5 pb-5 lh-n fcb-5"
to={URLS.GLOBAL_CONFIG_CLUSTER}
>
<Add data-testid="add_cluster_button" className="icon-dim-16 mr-4 fcb-5 dc__vertical-align-middle" />
Add cluster
</NavLink>
<Button
dataTestId="add_cluster_button"
text="Connect Cluster"
component={ButtonComponentType.link}
size={ComponentSizeType.small}
startIcon={<Add />}
linkProps={{
to: URLS.GLOBAL_CONFIG_CREATE_CLUSTER,
target: '_blank',
}}
/>
<span className="dc__divider" />
</div>
)
36 changes: 36 additions & 0 deletions src/components/ResourceBrowser/ResourceBrowser.service.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -77,6 +79,40 @@ export const getResourceData = async ({
return parseNodeList(response)
}

Copy link
Member

Choose a reason for hiding this comment

The 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)
Copy link
Member

Choose a reason for hiding this comment

The 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(
Copy link
Member

Choose a reason for hiding this comment

The 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,
Expand Down
Loading
Loading