From c05349bf67dc6bbb1009e2605dd748c6fa66be51 Mon Sep 17 00:00:00 2001 From: Anton Miniailo Date: Fri, 2 Feb 2024 17:52:45 -0500 Subject: [PATCH 1/8] Move EKS joinToken generation to the ManualHelm dialog. This token is used only for manul enrollment, automatic one generates token on the backend. --- .../EnrollEKSCluster/Dialogs.story.tsx | 127 +++++++++++++++--- .../EnrollEKSCluster/EnrollEksCluster.tsx | 31 ++--- .../EnrollEKSCluster/ManualHelmDialog.tsx | 27 +++- .../src/services/integrations/types.ts | 2 - 4 files changed, 150 insertions(+), 37 deletions(-) diff --git a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/Dialogs.story.tsx b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/Dialogs.story.tsx index c90f093de298b..3365bd4d0edee 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/Dialogs.story.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/Dialogs.story.tsx @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -import React from 'react'; +import React, { useEffect } from 'react'; import { MemoryRouter } from 'react-router'; import { rest } from 'msw'; import { mswLoader } from 'msw-storybook-addon'; @@ -27,15 +27,45 @@ import { ResourceKind } from 'teleport/Discover/Shared'; import { PingTeleportProvider } from 'teleport/Discover/Shared/PingTeleportContext'; import { ContextProvider } from 'teleport'; -import { generateCmd } from 'teleport/Discover/Kubernetes/HelmChart/HelmChart'; +const { worker } = window.msw; + +import { INTERNAL_RESOURCE_ID_LABEL_KEY } from 'teleport/services/joinToken'; +import { clearCachedJoinTokenResult } from 'teleport/Discover/Shared/useJoinTokenSuspender'; +import { + DiscoverContextState, + DiscoverProvider, +} from 'teleport/Discover/useDiscover'; +import { + IntegrationKind, + IntegrationStatusCode, +} from 'teleport/services/integrations'; +import { DiscoverEventResource } from 'teleport/services/userEvent'; -import { ManualHelmDialog } from './ManualHelmDialog'; -import { AgentWaitingDialog } from './AgentWaitingDialog'; import { EnrollmentDialog } from './EnrollmentDialog'; +import { AgentWaitingDialog } from './AgentWaitingDialog'; +import { ManualHelmDialog } from './ManualHelmDialog'; export default { title: 'Teleport/Discover/Kube/EnrollEksClusters/Dialogs', loaders: [mswLoader], + decorators: [ + Story => { + worker.resetHandlers(); + + useEffect(() => { + // Clean up + return () => { + clearCachedJoinTokenResult([ + ResourceKind.Kubernetes, + ResourceKind.Application, + ResourceKind.Discovery, + ]); + }; + }, []); + + return ; + }, + ], }; export const EnrollmentDialogStory = () => ( @@ -110,7 +140,7 @@ AgentWaitingDialogSuccess.parameters = { }, }; -const helmCommand = generateCmd({ +const helmCommandProps = { namespace: 'teleport-agent', clusterName: 'EKS1', proxyAddr: 'teleport-proxy.example.com:1234', @@ -126,15 +156,82 @@ const helmCommand = generateCmd({ { name: 'region', value: 'us-east-1' }, { name: 'account-id', value: '1234567789012' }, ], -}); +}; -export const ManualHelmDialogStory = () => ( - - {}} - cancel={() => {}} - /> - -); +export const ManualHelmDialogStory = () => { + const discoverCtx: DiscoverContextState = { + agentMeta: { + resourceName: 'kube-name', + agentMatcherLabels: [], + kube: { + kind: 'kube_cluster', + name: '', + labels: [], + }, + awsIntegration: { + kind: IntegrationKind.AwsOidc, + name: 'test-oidc', + resourceType: 'integration', + spec: { + roleArn: 'arn:aws:iam::123456789012:role/test-role-arn', + }, + statusCode: IntegrationStatusCode.Running, + }, + }, + currentStep: 0, + nextStep: () => null, + prevStep: () => null, + onSelectResource: () => null, + resourceSpec: { + name: 'Eks', + kind: ResourceKind.Kubernetes, + icon: 'Eks', + keywords: '', + event: DiscoverEventResource.KubernetesEks, + }, + exitFlow: () => null, + viewConfig: null, + indexedViews: [], + setResourceSpec: () => null, + updateAgentMeta: () => null, + emitErrorEvent: () => null, + emitEvent: () => null, + eventState: null, + }; + + return ( + + + + {}} + confirmedCommands={() => {}} + cancel={() => {}} + /> + + + + ); +}; ManualHelmDialogStory.storyName = 'ManualHelmDialog'; +ManualHelmDialogStory.parameters = { + msw: { + handlers: [ + rest.post(cfg.api.joinTokenPath, (req, res, ctx) => { + return res( + ctx.json({ + id: 'token-id', + suggestedLabels: [ + { name: INTERNAL_RESOURCE_ID_LABEL_KEY, value: 'resource-id' }, + ], + }) + ); + }), + ], + }, +}; diff --git a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx index 583c391fd252a..840f9cdad6423 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx @@ -39,11 +39,12 @@ import { isIamPermError } from 'teleport/Discover/Shared/Aws/error'; import { AgentStepProps } from 'teleport/Discover/types'; import useTeleport from 'teleport/useTeleport'; -import { useJoinTokenSuspender } from 'teleport/Discover/Shared/useJoinTokenSuspender'; -import { generateCmd } from 'teleport/Discover/Kubernetes/HelmChart/HelmChart'; +import { GenerateCmdProps } from 'teleport/Discover/Kubernetes/HelmChart/HelmChart'; import { Kube } from 'teleport/services/kube'; -import { Header, ResourceKind } from '../../Shared'; +import { JoinToken } from 'teleport/services/joinToken'; + +import { Header } from '../../Shared'; import { ClustersList } from './EksClustersList'; import { ManualHelmDialog } from './ManualHelmDialog'; @@ -97,14 +98,9 @@ export function EnrollEksCluster(props: AgentStepProps) { useState(false); const [isManualHelmDialogShown, setIsManualHelmDialogShown] = useState(false); const [waitingResourceId, setWaitingResourceId] = useState(''); + const [joinToken, setJoinToken] = useState(null); const ctx = useTeleport(); - const { joinToken } = useJoinTokenSuspender([ - ResourceKind.Kubernetes, - ResourceKind.Application, - ResourceKind.Discovery, - ]); - function fetchClustersWithNewRegion(region: Regions) { setSelectedRegion(region); // Clear table when fetching with new region. @@ -205,8 +201,6 @@ export function EnrollEksCluster(props: AgentStepProps) { { region: selectedRegion, enableAppDiscovery: isAppDiscoveryEnabled, - joinToken: joinToken.id, - resourceId: joinToken.internalResourceId, clusterNames: [selectedCluster.name], } ); @@ -262,22 +256,22 @@ export function EnrollEksCluster(props: AgentStepProps) { !selectedCluster || enrollmentState.status !== 'notStarted'; - let command = ''; + let manualCommandProps: GenerateCmdProps = null; if (selectedCluster) { - command = generateCmd({ + manualCommandProps = { namespace: 'teleport-agent', clusterName: selectedCluster.name, proxyAddr: ctx.storeUser.state.cluster.publicURL, - tokenId: joinToken.id, clusterVersion: ctx.storeUser.state.cluster.authVersion, - resourceId: joinToken.internalResourceId, + tokenId: '', // Filled in by the ManualHelmDialog. + resourceId: '', isEnterprise: ctx.isEnterprise, isCloud: ctx.isCloud, automaticUpgradesEnabled: ctx.automaticUpgradesEnabled, automaticUpgradesTargetVersion: ctx.automaticUpgradesTargetVersion, joinLabels: [...selectedCluster.labels, ...selectedCluster.joinLabels], disableAppDiscovery: !isAppDiscoveryEnabled, - }); + }; } return ( @@ -366,7 +360,8 @@ export function EnrollEksCluster(props: AgentStepProps) { )} {isManualHelmDialogShown && ( setIsManualHelmDialogShown(false)} confirmedCommands={() => { setEnrollmentState({ status: 'awaitingAgent' }); @@ -377,7 +372,7 @@ export function EnrollEksCluster(props: AgentStepProps) { )} {isAgentWaitingDialogShown && ( { diff --git a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx index ce2a0428fd4b8..35a04e5efdd5f 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx @@ -23,20 +23,43 @@ import React from 'react'; import styled from 'styled-components'; +import { + GenerateCmdProps, + generateCmd, +} from 'teleport/Discover/Kubernetes/HelmChart/HelmChart'; import { TextSelectCopyMulti } from 'teleport/components/TextSelectCopy'; import { CommandBox } from 'teleport/Discover/Shared/CommandBox'; +import { useJoinTokenSuspender } from 'teleport/Discover/Shared/useJoinTokenSuspender'; +import { ResourceKind } from 'teleport/Discover/Shared'; +import { JoinToken } from 'teleport/services/joinToken'; + type ManualHelmDialogProps = { - command: string; + commandProps: GenerateCmdProps; + setJoinToken(token: JoinToken): void; confirmedCommands(): void; cancel(): void; }; export function ManualHelmDialog({ - command, + commandProps, + setJoinToken, cancel, confirmedCommands, }: ManualHelmDialogProps) { + const { joinToken } = useJoinTokenSuspender([ + ResourceKind.Kubernetes, + ResourceKind.Application, + ResourceKind.Discovery, + ]); + + setJoinToken(joinToken); + const command = generateCmd({ + ...commandProps, + tokenId: joinToken.id, + resourceId: joinToken.internalResourceId, + }); + return ( diff --git a/web/packages/teleport/src/services/integrations/types.ts b/web/packages/teleport/src/services/integrations/types.ts index 8094c0072e3d1..cf99cdc3c75a6 100644 --- a/web/packages/teleport/src/services/integrations/types.ts +++ b/web/packages/teleport/src/services/integrations/types.ts @@ -317,8 +317,6 @@ export type AwsEksCluster = { export type EnrollEksClustersRequest = { region: string; enableAppDiscovery: boolean; - joinToken: string; - resourceId: string; clusterNames: string[]; }; From 52f6cf750dadd250b98a0f9bdfd79e6f00708356 Mon Sep 17 00:00:00 2001 From: Anton Miniailo Date: Wed, 21 Feb 2024 17:24:47 -0500 Subject: [PATCH 2/8] Add container to manual helm dialog. --- .../EnrollEKSCluster/EnrollEksCluster.tsx | 2 +- .../EnrollEKSCluster/ManualHelmDialog.tsx | 81 ++++++++++++++++++- 2 files changed, 80 insertions(+), 3 deletions(-) diff --git a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx index 840f9cdad6423..946fa8c1ab2d4 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx @@ -47,7 +47,7 @@ import { JoinToken } from 'teleport/services/joinToken'; import { Header } from '../../Shared'; import { ClustersList } from './EksClustersList'; -import { ManualHelmDialog } from './ManualHelmDialog'; +import ManualHelmDialog from './ManualHelmDialog'; import { EnrollmentDialog } from './EnrollmentDialog'; import { AgentWaitingDialog } from './AgentWaitingDialog'; diff --git a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx index 35a04e5efdd5f..c77084cd9705e 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx @@ -19,10 +19,14 @@ import Dialog, { DialogContent, DialogFooter } from 'design/DialogConfirmation'; import { Box, Flex, ButtonPrimary, ButtonSecondary, Text } from 'design'; -import React from 'react'; +import React, { Suspense } from 'react'; import styled from 'styled-components'; +import { Spinner } from 'design/Icon'; + +import * as Icons from 'design/Icon'; + import { GenerateCmdProps, generateCmd, @@ -31,8 +35,10 @@ import { TextSelectCopyMulti } from 'teleport/components/TextSelectCopy'; import { CommandBox } from 'teleport/Discover/Shared/CommandBox'; import { useJoinTokenSuspender } from 'teleport/Discover/Shared/useJoinTokenSuspender'; -import { ResourceKind } from 'teleport/Discover/Shared'; +import { ResourceKind, TextIcon } from 'teleport/Discover/Shared'; import { JoinToken } from 'teleport/services/joinToken'; +import { CatchError } from 'teleport/components/CatchError'; + type ManualHelmDialogProps = { commandProps: GenerateCmdProps; @@ -41,6 +47,63 @@ type ManualHelmDialogProps = { cancel(): void; }; +export default function Container(props: ManualHelmDialogProps) { + return ( + ( + + )} + > + } + > + + + + ); +} + +type DummyDialogProps = { + cancel: () => void; + error?: Error; + showSpinner?: boolean; +}; + +const DummyDialog = ({ error, cancel, showSpinner }: DummyDialogProps) => { + return ( + + + + Manual EKS Cluster Enrollment + + {showSpinner && ( + + + + + + )} + {error && ( + + + + Encountered an error: {error.message} + + + )} + + + {}} disabled> + I ran these commands + + + Cancel + + + + ); +}; + export function ManualHelmDialog({ commandProps, setJoinToken, @@ -112,3 +175,17 @@ const StyledBox = styled(Box)` padding: ${props => `${props.theme.space[3]}px`}; border-radius: ${props => `${props.theme.space[2]}px`}; `; + +const Spin = styled(Box)` + line-height: 12px; + font-size: 24px; + animation: spin 1s linear infinite; + @keyframes spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } + } +`; From 55f8214121fea856e215a37987af1bdcdd08c244 Mon Sep 17 00:00:00 2001 From: Anton Miniailo Date: Wed, 21 Feb 2024 17:30:23 -0500 Subject: [PATCH 3/8] Document join creation delay reason. --- .../Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx index 946fa8c1ab2d4..53b415aea07da 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx @@ -98,6 +98,8 @@ export function EnrollEksCluster(props: AgentStepProps) { useState(false); const [isManualHelmDialogShown, setIsManualHelmDialogShown] = useState(false); const [waitingResourceId, setWaitingResourceId] = useState(''); + // join token will be set only if user opens ManualHelmDialog, + // we delay it to avoid premature admin action MFA confirmation request. const [joinToken, setJoinToken] = useState(null); const ctx = useTeleport(); From 5fafad1d93fa689e1072b7f7692d68326ce05168 Mon Sep 17 00:00:00 2001 From: Anton Miniailo Date: Wed, 21 Feb 2024 20:48:09 -0500 Subject: [PATCH 4/8] Remove usage of msw. --- .../EnrollEKSCluster/Dialogs.story.tsx | 30 +++++++------------ 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/Dialogs.story.tsx b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/Dialogs.story.tsx index 3365bd4d0edee..466591abec3af 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/Dialogs.story.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/Dialogs.story.tsx @@ -27,8 +27,6 @@ import { ResourceKind } from 'teleport/Discover/Shared'; import { PingTeleportProvider } from 'teleport/Discover/Shared/PingTeleportContext'; import { ContextProvider } from 'teleport'; -const { worker } = window.msw; - import { INTERNAL_RESOURCE_ID_LABEL_KEY } from 'teleport/services/joinToken'; import { clearCachedJoinTokenResult } from 'teleport/Discover/Shared/useJoinTokenSuspender'; import { @@ -48,24 +46,6 @@ import { ManualHelmDialog } from './ManualHelmDialog'; export default { title: 'Teleport/Discover/Kube/EnrollEksClusters/Dialogs', loaders: [mswLoader], - decorators: [ - Story => { - worker.resetHandlers(); - - useEffect(() => { - // Clean up - return () => { - clearCachedJoinTokenResult([ - ResourceKind.Kubernetes, - ResourceKind.Application, - ResourceKind.Discovery, - ]); - }; - }, []); - - return ; - }, - ], }; export const EnrollmentDialogStory = () => ( @@ -199,6 +179,16 @@ export const ManualHelmDialogStory = () => { eventState: null, }; + useEffect(() => { + return () => { + clearCachedJoinTokenResult([ + ResourceKind.Kubernetes, + ResourceKind.Application, + ResourceKind.Discovery, + ]); + }; + }, []); + return ( Date: Wed, 21 Feb 2024 21:19:05 -0500 Subject: [PATCH 5/8] Generate command outside of manualHelmDialog. --- .../EnrollEKSCluster/Dialogs.story.tsx | 5 +++-- .../EnrollEKSCluster/EnrollEksCluster.tsx | 19 +++++++++---------- .../EnrollEKSCluster/ManualHelmDialog.tsx | 18 +++--------------- 3 files changed, 15 insertions(+), 27 deletions(-) diff --git a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/Dialogs.story.tsx b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/Dialogs.story.tsx index 466591abec3af..7e5682ba1367b 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/Dialogs.story.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/Dialogs.story.tsx @@ -39,6 +39,8 @@ import { } from 'teleport/services/integrations'; import { DiscoverEventResource } from 'teleport/services/userEvent'; +import { generateCmd } from 'teleport/Discover/Kubernetes/HelmChart/HelmChart'; + import { EnrollmentDialog } from './EnrollmentDialog'; import { AgentWaitingDialog } from './AgentWaitingDialog'; import { ManualHelmDialog } from './ManualHelmDialog'; @@ -198,8 +200,7 @@ export const ManualHelmDialogStory = () => { {}} + setJoinTokenAndGetCommand={() => generateCmd(helmCommandProps)} confirmedCommands={() => {}} cancel={() => {}} /> diff --git a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx index 53b415aea07da..ccecd12b36f0a 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx @@ -39,7 +39,7 @@ import { isIamPermError } from 'teleport/Discover/Shared/Aws/error'; import { AgentStepProps } from 'teleport/Discover/types'; import useTeleport from 'teleport/useTeleport'; -import { GenerateCmdProps } from 'teleport/Discover/Kubernetes/HelmChart/HelmChart'; +import { generateCmd } from 'teleport/Discover/Kubernetes/HelmChart/HelmChart'; import { Kube } from 'teleport/services/kube'; import { JoinToken } from 'teleport/services/joinToken'; @@ -258,23 +258,23 @@ export function EnrollEksCluster(props: AgentStepProps) { !selectedCluster || enrollmentState.status !== 'notStarted'; - let manualCommandProps: GenerateCmdProps = null; - if (selectedCluster) { - manualCommandProps = { + const setJoinTokenAndGetCommand = (token: JoinToken) => { + setJoinToken(token); + return generateCmd({ namespace: 'teleport-agent', clusterName: selectedCluster.name, proxyAddr: ctx.storeUser.state.cluster.publicURL, clusterVersion: ctx.storeUser.state.cluster.authVersion, - tokenId: '', // Filled in by the ManualHelmDialog. - resourceId: '', + tokenId: token.id, + resourceId: token.internalResourceId, isEnterprise: ctx.isEnterprise, isCloud: ctx.isCloud, automaticUpgradesEnabled: ctx.automaticUpgradesEnabled, automaticUpgradesTargetVersion: ctx.automaticUpgradesTargetVersion, joinLabels: [...selectedCluster.labels, ...selectedCluster.joinLabels], disableAppDiscovery: !isAppDiscoveryEnabled, - }; - } + }); + }; return ( @@ -362,8 +362,7 @@ export function EnrollEksCluster(props: AgentStepProps) { )} {isManualHelmDialogShown && ( setIsManualHelmDialogShown(false)} confirmedCommands={() => { setEnrollmentState({ status: 'awaitingAgent' }); diff --git a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx index c77084cd9705e..0bde343c3c501 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx @@ -27,10 +27,6 @@ import { Spinner } from 'design/Icon'; import * as Icons from 'design/Icon'; -import { - GenerateCmdProps, - generateCmd, -} from 'teleport/Discover/Kubernetes/HelmChart/HelmChart'; import { TextSelectCopyMulti } from 'teleport/components/TextSelectCopy'; import { CommandBox } from 'teleport/Discover/Shared/CommandBox'; @@ -39,10 +35,8 @@ import { ResourceKind, TextIcon } from 'teleport/Discover/Shared'; import { JoinToken } from 'teleport/services/joinToken'; import { CatchError } from 'teleport/components/CatchError'; - type ManualHelmDialogProps = { - commandProps: GenerateCmdProps; - setJoinToken(token: JoinToken): void; + setJoinTokenAndGetCommand(token: JoinToken): string; confirmedCommands(): void; cancel(): void; }; @@ -105,8 +99,7 @@ const DummyDialog = ({ error, cancel, showSpinner }: DummyDialogProps) => { }; export function ManualHelmDialog({ - commandProps, - setJoinToken, + setJoinTokenAndGetCommand, cancel, confirmedCommands, }: ManualHelmDialogProps) { @@ -116,12 +109,7 @@ export function ManualHelmDialog({ ResourceKind.Discovery, ]); - setJoinToken(joinToken); - const command = generateCmd({ - ...commandProps, - tokenId: joinToken.id, - resourceId: joinToken.internalResourceId, - }); + const command = setJoinTokenAndGetCommand(joinToken); return ( From e67ad980cf3858b3e852f93fa9473a9b5196f12b Mon Sep 17 00:00:00 2001 From: Anton Miniailo Date: Thu, 22 Feb 2024 22:00:42 -0500 Subject: [PATCH 6/8] Fix setting join token in the manual helm dialog. --- .../EnrollEKSCluster/Dialogs.story.tsx | 16 +++++-- .../EnrollEKSCluster/EnrollEksCluster.tsx | 47 ++++++++++++------- .../EnrollEKSCluster/ManualHelmDialog.tsx | 9 +++- 3 files changed, 49 insertions(+), 23 deletions(-) diff --git a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/Dialogs.story.tsx b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/Dialogs.story.tsx index 7e5682ba1367b..39e9ad759c92a 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/Dialogs.story.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/Dialogs.story.tsx @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -import React, { useEffect } from 'react'; +import React, { useEffect, useState } from 'react'; import { MemoryRouter } from 'react-router'; import { rest } from 'msw'; import { mswLoader } from 'msw-storybook-addon'; @@ -27,7 +27,10 @@ import { ResourceKind } from 'teleport/Discover/Shared'; import { PingTeleportProvider } from 'teleport/Discover/Shared/PingTeleportContext'; import { ContextProvider } from 'teleport'; -import { INTERNAL_RESOURCE_ID_LABEL_KEY } from 'teleport/services/joinToken'; +import { + INTERNAL_RESOURCE_ID_LABEL_KEY, + JoinToken, +} from 'teleport/services/joinToken'; import { clearCachedJoinTokenResult } from 'teleport/Discover/Shared/useJoinTokenSuspender'; import { DiscoverContextState, @@ -191,6 +194,8 @@ export const ManualHelmDialogStory = () => { }; }, []); + const [, setToken] = useState(); + return ( { generateCmd(helmCommandProps)} + setJoinTokenAndGetCommand={token => { + // Emulate real usage of ManualHelmDialog where setJoinTokenAndGetCommand updates the + // state of a parent. + setToken(token); + return generateCmd(helmCommandProps); + }} confirmedCommands={() => {}} cancel={() => {}} /> diff --git a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx index ccecd12b36f0a..699e3456d7ca0 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -import React, { useState } from 'react'; +import React, { useState, useCallback } from 'react'; import { Box, ButtonSecondary, ButtonText, Text, Toggle } from 'design'; import styled from 'styled-components'; import { FetchStatus } from 'design/DataTable/types'; @@ -258,23 +258,34 @@ export function EnrollEksCluster(props: AgentStepProps) { !selectedCluster || enrollmentState.status !== 'notStarted'; - const setJoinTokenAndGetCommand = (token: JoinToken) => { - setJoinToken(token); - return generateCmd({ - namespace: 'teleport-agent', - clusterName: selectedCluster.name, - proxyAddr: ctx.storeUser.state.cluster.publicURL, - clusterVersion: ctx.storeUser.state.cluster.authVersion, - tokenId: token.id, - resourceId: token.internalResourceId, - isEnterprise: ctx.isEnterprise, - isCloud: ctx.isCloud, - automaticUpgradesEnabled: ctx.automaticUpgradesEnabled, - automaticUpgradesTargetVersion: ctx.automaticUpgradesTargetVersion, - joinLabels: [...selectedCluster.labels, ...selectedCluster.joinLabels], - disableAppDiscovery: !isAppDiscoveryEnabled, - }); - }; + const setJoinTokenAndGetCommand = useCallback( + (token: JoinToken) => { + setJoinToken(token); + return generateCmd({ + namespace: 'teleport-agent', + clusterName: selectedCluster.name, + proxyAddr: ctx.storeUser.state.cluster.publicURL, + clusterVersion: ctx.storeUser.state.cluster.authVersion, + tokenId: token.id, + resourceId: token.internalResourceId, + isEnterprise: ctx.isEnterprise, + isCloud: ctx.isCloud, + automaticUpgradesEnabled: ctx.automaticUpgradesEnabled, + automaticUpgradesTargetVersion: ctx.automaticUpgradesTargetVersion, + joinLabels: [...selectedCluster.labels, ...selectedCluster.joinLabels], + disableAppDiscovery: !isAppDiscoveryEnabled, + }); + }, + [ + ctx.automaticUpgradesEnabled, + ctx.automaticUpgradesTargetVersion, + ctx.isCloud, + ctx.isEnterprise, + ctx.storeUser.state.cluster, + isAppDiscoveryEnabled, + selectedCluster, + ] + ); return ( diff --git a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx index 0bde343c3c501..832822c432528 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx @@ -19,7 +19,7 @@ import Dialog, { DialogContent, DialogFooter } from 'design/DialogConfirmation'; import { Box, Flex, ButtonPrimary, ButtonSecondary, Text } from 'design'; -import React, { Suspense } from 'react'; +import React, { Suspense, useState, useEffect } from 'react'; import styled from 'styled-components'; @@ -108,8 +108,13 @@ export function ManualHelmDialog({ ResourceKind.Application, ResourceKind.Discovery, ]); + const [command, setCommand] = useState(''); - const command = setJoinTokenAndGetCommand(joinToken); + useEffect(() => { + if (joinToken && !command) { + setCommand(setJoinTokenAndGetCommand(joinToken)); + } + }, [joinToken, command, setJoinTokenAndGetCommand]); return ( From 8faf471dba46c7502cf4417f700e051d56a82cf5 Mon Sep 17 00:00:00 2001 From: Anton Miniailo Date: Thu, 22 Feb 2024 22:22:12 -0500 Subject: [PATCH 7/8] Refactor dummyDialog. --- .../EnrollEKSCluster/ManualHelmDialog.tsx | 129 +++++++++--------- 1 file changed, 68 insertions(+), 61 deletions(-) diff --git a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx index 832822c432528..4c3fa41ed61e4 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx @@ -45,11 +45,11 @@ export default function Container(props: ManualHelmDialogProps) { return ( ( - + )} > } + fallback={} > @@ -57,37 +57,31 @@ export default function Container(props: ManualHelmDialogProps) { ); } -type DummyDialogProps = { +type FallbackDialogProps = { cancel: () => void; error?: Error; showSpinner?: boolean; }; -const DummyDialog = ({ error, cancel, showSpinner }: DummyDialogProps) => { +const DialogWrapper = ({ + children, + cancel, + next, +}: { + children: React.ReactNode; + cancel: () => void; + next?: () => void; +}) => { return ( Manual EKS Cluster Enrollment - {showSpinner && ( - - - - - - )} - {error && ( - - - - Encountered an error: {error.message} - - - )} + {children} - {}} disabled> + I ran these commands @@ -98,6 +92,32 @@ const DummyDialog = ({ error, cancel, showSpinner }: DummyDialogProps) => { ); }; +const FallbackDialog = ({ + error, + cancel, + showSpinner, +}: FallbackDialogProps) => { + return ( + + {showSpinner && ( + + + + + + )} + {error && ( + + + + Encountered an error: {error.message} + + + )} + + ); +}; + export function ManualHelmDialog({ setJoinTokenAndGetCommand, cancel, @@ -117,48 +137,35 @@ export function ManualHelmDialog({ }, [joinToken, command, setJoinTokenAndGetCommand]); return ( - - - - Manual EKS Cluster Enrollment + + + Step 1 + + Add teleport-agent chart to your charts repository - - Step 1 - - Add teleport-agent chart to your charts repository - - - - - Step 2 - - Run the command below on the server your target EKS cluster is - at. It may take up to a minute for the Teleport Service to join - after running the command. - - - } - > - - - - - - I ran these commands - - - Cancel - - - + + + + Step 2 + + Run the command below on the server your target EKS cluster is at. + It may take up to a minute for the Teleport Service to join after + running the command. + + + } + > + + + ); } From 2f7a4016f54dfabf2658bb7b84dcd381e1780e5d Mon Sep 17 00:00:00 2001 From: Anton Miniailo Date: Fri, 23 Feb 2024 12:00:23 -0500 Subject: [PATCH 8/8] Use indicator component. --- .../EnrollEKSCluster/ManualHelmDialog.tsx | 32 +++++++------------ 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx index 4c3fa41ed61e4..593f1722b3227 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx @@ -17,14 +17,19 @@ */ import Dialog, { DialogContent, DialogFooter } from 'design/DialogConfirmation'; -import { Box, Flex, ButtonPrimary, ButtonSecondary, Text } from 'design'; +import { + Box, + Flex, + ButtonPrimary, + ButtonSecondary, + Text, + Indicator, +} from 'design'; import React, { Suspense, useState, useEffect } from 'react'; import styled from 'styled-components'; -import { Spinner } from 'design/Icon'; - import * as Icons from 'design/Icon'; import { TextSelectCopyMulti } from 'teleport/components/TextSelectCopy'; @@ -51,7 +56,8 @@ export default function Container(props: ManualHelmDialogProps) { } > - + {/**/} + fallback={} ); @@ -101,9 +107,7 @@ const FallbackDialog = ({ {showSpinner && ( - - - + )} {error && ( @@ -175,17 +179,3 @@ const StyledBox = styled(Box)` padding: ${props => `${props.theme.space[3]}px`}; border-radius: ${props => `${props.theme.space[2]}px`}; `; - -const Spin = styled(Box)` - line-height: 12px; - font-size: 24px; - animation: spin 1s linear infinite; - @keyframes spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } - } -`;