Skip to content

Commit

Permalink
feat: Add node drain functionality to dashboard (#1376)
Browse files Browse the repository at this point in the history
  • Loading branch information
maciaszczykm authored Sep 17, 2024
1 parent 65eab4f commit 14fe7a5
Show file tree
Hide file tree
Showing 24 changed files with 210 additions and 33 deletions.
42 changes: 35 additions & 7 deletions assets/schema/kubernetes-schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -3823,7 +3823,7 @@ type v1_ConfigMapKeySelector {
"""The key to select."""
key: String!
"""
Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
"""
name: String
"""Specify whether the ConfigMap or its key must be defined"""
Expand Down Expand Up @@ -3863,7 +3863,7 @@ type v1_SecretKeySelector {
"""The key of the secret to select from. Must be a valid secret key."""
key: String!
"""
Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
"""
name: String
"""Specify whether the Secret or its key must be defined"""
Expand Down Expand Up @@ -4335,7 +4335,7 @@ LocalObjectReference contains enough information to let you locate the reference
"""
type v1_LocalObjectReference {
"""
Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
"""
name: String
}
Expand Down Expand Up @@ -4374,7 +4374,7 @@ type v1_ConfigMapVolumeSource {
"""
items: [v1_KeyToPath]
"""
Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
"""
name: String
"""optional specify whether the ConfigMap or its keys must be defined"""
Expand Down Expand Up @@ -4855,7 +4855,7 @@ type v1_ConfigMapProjection {
"""
items: [v1_KeyToPath]
"""
Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
"""
name: String
"""optional specify whether the ConfigMap or its keys must be defined"""
Expand All @@ -4881,7 +4881,7 @@ type v1_SecretProjection {
"""
items: [v1_KeyToPath]
"""
Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
"""
name: String
"""optional field specify whether the Secret or its key must be defined"""
Expand Down Expand Up @@ -5554,6 +5554,26 @@ type Mutation {
aggregations: String
input: namespace_NamespaceSpec_Input!
): namespace_NamespaceSpec! @httpOperation(subgraph: "api", path: "/api/v1/namespace", operationSpecificHeaders: "{\"Content-Type\":\"application/json\",\"Accept\":\"application/json\"}", httpMethod: POST, queryParamArgMap: "{\"filterBy\":\"filterBy\",\"sortBy\":\"sortBy\",\"itemsPerPage\":\"itemsPerPage\",\"page\":\"page\",\"metricNames\":\"metricNames\",\"aggregations\":\"aggregations\"}")
"""drains Node"""
handleNodeDrain(
"""name of the Node"""
name: String!
"""
Comma delimited string used to apply filtering: 'propertyName,filterValue'
"""
filterBy: String
"""Name of the column to sort by"""
sortBy: String
"""Number of items to return when pagination is applied"""
itemsPerPage: String
"""Page number to return items from"""
page: String
"""Metric names to download"""
metricNames: String
"""Aggregations to be performed for each metric (default: sum)"""
aggregations: String
input: node_NodeDrainSpec_Input!
): JSON @httpOperation(subgraph: "api", path: "/api/v1/node/{args.name}/drain", operationSpecificHeaders: "{\"Content-Type\":\"application/json\",\"Accept\":\"application/json\"}", httpMethod: PUT, queryParamArgMap: "{\"filterBy\":\"filterBy\",\"sortBy\":\"sortBy\",\"itemsPerPage\":\"itemsPerPage\",\"page\":\"page\",\"metricNames\":\"metricNames\",\"aggregations\":\"aggregations\"}")
"""scales ReplicationController to a number of replicas"""
handleUpdateReplicasCount(
"""namespace of the ReplicationController"""
Expand Down Expand Up @@ -5774,6 +5794,14 @@ input namespace_NamespaceSpec_Input {
name: String!
}

input node_NodeDrainSpec_Input {
deleteEmptyDirData: Boolean
force: Boolean
gracePeriodSeconds: Int
ignoreAllDaemonSets: Boolean
timeout: BigInt
}

input replicationcontroller_ReplicationControllerSpec_Input {
replicas: Int!
}
Expand Down Expand Up @@ -5817,4 +5845,4 @@ type StringWrapper {

type StateWrapper {
state: ContainerState!
}
}
12 changes: 10 additions & 2 deletions assets/src/components/kubernetes/cluster/Node.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { ReactElement, useMemo } from 'react'
import {
Card,
Chip,
ChipList,
SidecarItem,
Table,
Expand Down Expand Up @@ -98,9 +99,16 @@ export default function Node(): ReactElement {
<ResourceReadyChip ready={node?.ready} />
</SidecarItem>
<SidecarItem heading="Unschedulable">
{node?.unschedulable ? 'True' : 'False'}
<Chip
size="small"
severity={node?.unschedulable ? 'danger' : 'success'}
>
{node?.unschedulable ? 'True' : 'False'}
</Chip>
</SidecarItem>
<SidecarItem heading="Pod CIDR">{node?.podCIDR}</SidecarItem>
{node.podCIDR && (
<SidecarItem heading="Pod CIDR">{node?.podCIDR}</SidecarItem>
)}
</MetadataSidecar>
}
>
Expand Down
73 changes: 71 additions & 2 deletions assets/src/components/kubernetes/cluster/Nodes.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
import { createColumnHelper } from '@tanstack/react-table'
import { useMemo } from 'react'
import { useMemo, useState } from 'react'
import { filesize } from 'filesize'
import { useSetBreadcrumbs } from '@pluralsh/design-system'
import {
IconFrame,
SortDescIcon,
Switch,
useSetBreadcrumbs,
} from '@pluralsh/design-system'

import { useTheme } from 'styled-components'

import {
DrainNodeMutationVariables,
Maybe,
Node_NodeList as NodeListT,
Node_Node as NodeT,
NodesQuery,
NodesQueryVariables,
useDrainNodeMutation,
useNodesQuery,
} from '../../../generated/graphql-kubernetes'
import { ResourceReadyChip, useDefaultColumns } from '../common/utils'
Expand All @@ -22,6 +31,10 @@ import {
} from '../../../routes/kubernetesRoutesConsts'
import { useCluster } from '../Cluster'

import { Confirm } from '../../utils/Confirm'

import { KubernetesClient } from '../../../helpers/kubernetes.client'

import { getClusterBreadcrumbs } from './Cluster'

export const getBreadcrumbs = (cluster?: Maybe<KubernetesClusterFragment>) => [
Expand Down Expand Up @@ -103,6 +116,61 @@ const colPods = columnHelper.accessor((node) => node?.allocatedResources, {
},
})

const colActions = columnHelper.accessor(() => null, {
id: 'actions',
header: '',
cell: function Cell({ row: { original } }) {
const theme = useTheme()
const cluster = useCluster()
const [open, setOpen] = useState(false)
const [ignoreAllDaemonSets, setIgnoreAllDaemonSets] = useState(true)
const [mutation, { loading, error }] = useDrainNodeMutation({
client: KubernetesClient(cluster?.id ?? ''),
variables: {
name: original.objectMeta.name ?? '',
input: { ignoreAllDaemonSets },
} as DrainNodeMutationVariables,
onCompleted: () => setOpen(false),
})

return (
<>
<IconFrame
clickable
icon={<SortDescIcon color="icon-danger" />}
tooltip="Drain node"
onClick={(e) => {
e.stopPropagation()
setOpen(true)
}}
/>
{open && (
<Confirm
close={() => setOpen(false)}
destructive
label="Drain node"
loading={loading}
error={error}
open={open}
submit={() => mutation()}
title="Drain node"
text={`Are you sure you want to drain ${original?.objectMeta.name} node? Node will be cordoned first. Please note that it may take a while to complete.`}
extraContent={
<Switch
checked={ignoreAllDaemonSets}
onChange={setIgnoreAllDaemonSets}
css={{ paddingTop: theme.spacing.medium }}
>
Ignore all daemon sets
</Switch>
}
/>
)}
</>
)
},
})

export default function Nodes() {
const cluster = useCluster()

Expand All @@ -119,6 +187,7 @@ export default function Nodes() {
colPods,
colLabels,
colCreationTimestamp,
colActions,
],
[colName, colLabels, colCreationTimestamp]
)
Expand Down
6 changes: 5 additions & 1 deletion assets/src/components/kubernetes/common/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import moment from 'moment/moment'
import yaml from 'js-yaml'
import { capitalize } from 'lodash'

import { ChipProps } from '@pluralsh/design-system/dist/components/Chip'

import {
Types_ListMeta as ListMetaT,
Maybe,
Expand Down Expand Up @@ -110,9 +112,10 @@ const resourceConditionSeverity = {

export function ResourceReadyChip({
ready,
...props
}: {
ready: string | boolean | undefined
}) {
} & ChipProps) {
if (ready === undefined) return undefined

const r = ready.toString()
Expand All @@ -122,6 +125,7 @@ export function ResourceReadyChip({
<Chip
size="small"
severity={severity}
{...props}
>
{capitalize(r)}
</Chip>
Expand Down
Loading

0 comments on commit 14fe7a5

Please sign in to comment.