Skip to content

Commit

Permalink
Request token for roles kube,app,discovery in Kubernetes resource wiz…
Browse files Browse the repository at this point in the history
…ard (#30567)

* Request token for roles kube,app,discovery in Kubernetes resource wizard

Refactored useJoinTokenSuspender to accept array of resource kinds instead of
a single kind.

* Use array instead of variable number of parameters

* Inject list of roles instead of hardcoding it
  • Loading branch information
AntonAM committed Aug 20, 2023
1 parent c584138 commit 9617ecf
Show file tree
Hide file tree
Showing 19 changed files with 61 additions and 35 deletions.
Expand Up @@ -31,7 +31,7 @@ export function DatabaseWrapper(props: DatabaseWrapperProps) {
useEffect(() => {
return () => {
// once the user leaves the desktop setup flow, delete the existing token
clearCachedJoinTokenResult(ResourceKind.Database);
clearCachedJoinTokenResult([ResourceKind.Database]);
};
}, []);

Expand Down
Expand Up @@ -82,7 +82,7 @@ export default function Container({ toggleDeployMethod }: DeployServiceProp) {
<Validation>
{({ validator }) => (
<CatchError
onRetry={() => clearCachedJoinTokenResult(ResourceKind.Database)}
onRetry={() => clearCachedJoinTokenResult([ResourceKind.Database])}
fallbackFn={fbProps => (
<Box>
{heading}
Expand Down Expand Up @@ -143,7 +143,7 @@ export function ManualDeploy(props: {

// Fetches join token.
const { joinToken } = useJoinTokenSuspender(
ResourceKind.Database,
[ResourceKind.Database],
props.labels
);

Expand Down
Expand Up @@ -33,9 +33,9 @@ export function useMutualTls({ ctx, props }: Props) {
const { attempt, run } = useAttempt('');

const { emitErrorEvent } = useDiscover();
const { joinToken: prevFetchedJoinToken } = useJoinTokenSuspender(
ResourceKind.Database
);
const { joinToken: prevFetchedJoinToken } = useJoinTokenSuspender([
ResourceKind.Database,
]);
const [joinToken, setJoinToken] = useState(prevFetchedJoinToken);
const meta = props.agentMeta as DbMeta;
const clusterId = ctx.storeUser.getClusterId();
Expand Down
Expand Up @@ -68,7 +68,7 @@ const states = (joinToken: JoinToken) => [
];

export function CreateTeleportConfigAnimation() {
const { joinToken } = useJoinTokenSuspender(ResourceKind.Desktop);
const { joinToken } = useJoinTokenSuspender([ResourceKind.Desktop]);

const [editorState, setEditorState] = useState(EditorState.Original);

Expand Down
Expand Up @@ -43,7 +43,7 @@ interface RunConfigureScriptProps {
export function RunConfigureScript(
props: React.PropsWithChildren<RunConfigureScriptProps>
) {
const { joinToken } = useJoinTokenSuspender(ResourceKind.Desktop);
const { joinToken } = useJoinTokenSuspender([ResourceKind.Desktop]);

const command = generateCommand(cfg.getConfigureADUrl(joinToken.id));

Expand Down
Expand Up @@ -109,7 +109,7 @@ interface RunConfigureScriptAnimationProps {
export function RunConfigureScriptAnimation(
props: RunConfigureScriptAnimationProps
) {
const { joinToken } = useJoinTokenSuspender(ResourceKind.Desktop);
const { joinToken } = useJoinTokenSuspender([ResourceKind.Desktop]);

return (
<AnimatedTerminal
Expand Down
Expand Up @@ -61,7 +61,7 @@ function StepWrapper(props: StepWrapperProps) {
export function StartTeleport(
props: React.PropsWithChildren<StartTeleportProps>
) {
const { joinToken } = useJoinTokenSuspender(ResourceKind.Desktop);
const { joinToken } = useJoinTokenSuspender([ResourceKind.Desktop]);
const { active, result } = usePingTeleport(joinToken);

const showHint = useShowHint(active);
Expand Down
Expand Up @@ -92,7 +92,7 @@ export function StartTeleportTerminalAnimation() {
const [animationFinished, setAnimationFinished] = useState(false);
const [lines, setLines] = useState<TerminalLine[]>([...startLines]);

const { joinToken } = useJoinTokenSuspender(ResourceKind.Desktop);
const { joinToken } = useJoinTokenSuspender([ResourceKind.Desktop]);
const { active, result } = usePingTeleport<WindowsDesktopService>(joinToken);

const [ranConnectingAnimation, setRanConnectingAnimation] = useState(false);
Expand Down
Expand Up @@ -31,7 +31,7 @@ export function DesktopWrapper(props: DesktopWrapperProps) {
useEffect(() => {
return () => {
// once the user leaves the desktop setup flow, delete the existing token
clearCachedJoinTokenResult(ResourceKind.Desktop);
clearCachedJoinTokenResult([ResourceKind.Desktop]);
};
}, []);

Expand Down
Expand Up @@ -101,7 +101,7 @@ export function DiscoverDesktops() {
const ctx = useTeleport();
const { emitEvent, nextStep } = useDiscover();

const { joinToken } = useJoinTokenSuspender(ResourceKind.Desktop);
const { joinToken } = useJoinTokenSuspender([ResourceKind.Desktop]);
const { result: desktopService, active } =
usePingTeleport<WindowsDesktopService>(joinToken);

Expand Down
Expand Up @@ -34,7 +34,7 @@ export default {
Story => {
// Reset request handlers added in individual stories.
worker.resetHandlers();
clearCachedJoinTokenResult(ResourceKind.Kubernetes);
clearCachedJoinTokenResult([ResourceKind.Kubernetes]);
return <Story />;
},
],
Expand Down
Expand Up @@ -41,16 +41,16 @@ import { CommandBox } from 'teleport/Discover/Shared/CommandBox';

import {
ActionButtons,
Header,
HeaderSubtitle,
Mark,
ResourceKind,
TextIcon,
useShowHint,
Header,
} from '../../Shared';

import type { AgentStepProps } from '../../types';
import type { JoinToken } from 'teleport/services/joinToken';
import type { JoinRole, JoinToken } from 'teleport/services/joinToken';
import type { AgentMeta, KubeMeta } from 'teleport/Discover/useDiscover';
import type { Kube } from 'teleport/services/kube';

Expand All @@ -63,7 +63,13 @@ export default function Container(props: AgentStepProps) {
// This outer CatchError and Suspense handles
// join token api fetch error and loading states.
<CatchError
onRetry={() => clearCachedJoinTokenResult(ResourceKind.Kubernetes)}
onRetry={() =>
clearCachedJoinTokenResult([
ResourceKind.Kubernetes,
ResourceKind.Application,
ResourceKind.Discovery,
])
}
fallbackFn={fallbackProps => (
<Box>
<Heading />
Expand Down Expand Up @@ -147,9 +153,11 @@ export function HelmChart(
setClusterName(c: string): void;
}
) {
const { joinToken, reloadJoinToken } = useJoinTokenSuspender(
ResourceKind.Kubernetes
);
const { joinToken, reloadJoinToken } = useJoinTokenSuspender([
ResourceKind.Kubernetes,
ResourceKind.Application,
ResourceKind.Discovery,
]);

return (
<Box>
Expand Down Expand Up @@ -318,6 +326,7 @@ const generateCmd = (data: {
isEnterprise: boolean;
isCloud: boolean;
automaticUpgradesEnabled: boolean;
roles: JoinRole[];
}) => {
let extraYAMLConfig = '';

Expand All @@ -336,8 +345,10 @@ const generateCmd = (data: {
extraYAMLConfig += ' minAvailable: 1\n';
}

const yamlRoles = data.roles.join(',').toLowerCase();

return `cat << EOF > prod-cluster-values.yaml
roles: kube
roles: ${yamlRoles}
authToken: ${data.tokenId}
proxyAddr: ${data.proxyAddr}
kubeClusterName: ${data.clusterName}
Expand Down Expand Up @@ -440,6 +451,7 @@ const InstallHelmChart = ({
isEnterprise: ctx.isEnterprise,
isCloud: ctx.isCloud,
automaticUpgradesEnabled: ctx.automaticUpgradesEnabled,
roles: ['Kube', 'App', 'Discovery'],
});

return (
Expand Down
Expand Up @@ -28,7 +28,7 @@ export function KubeWrapper(props: WrapperProps) {
useEffect(() => {
return () => {
// once the user leaves this flow, delete the existing token
clearCachedJoinTokenResult(ResourceKind.Kubernetes);
clearCachedJoinTokenResult([ResourceKind.Kubernetes]);
};
}, []);

Expand Down
Expand Up @@ -36,7 +36,7 @@ export default {
Story => {
// Reset request handlers added in individual stories.
worker.resetHandlers();
clearCachedJoinTokenResult(ResourceKind.Server);
clearCachedJoinTokenResult([ResourceKind.Server]);
return <Story />;
},
],
Expand Down
Expand Up @@ -56,7 +56,7 @@ const SHOW_HINT_TIMEOUT = 1000 * 60 * 5; // 5 minutes
export default function Container(props: AgentStepProps) {
return (
<CatchError
onRetry={() => clearCachedJoinTokenResult(ResourceKind.Server)}
onRetry={() => clearCachedJoinTokenResult([ResourceKind.Server])}
fallbackFn={fbProps => (
<Template prevStep={props.prevStep} nextStep={() => null}>
<TextIcon mt={2} mb={3}>
Expand Down Expand Up @@ -85,7 +85,7 @@ export default function Container(props: AgentStepProps) {

export function DownloadScript(props: AgentStepProps) {
// Fetches join token.
const { joinToken } = useJoinTokenSuspender(ResourceKind.Server);
const { joinToken } = useJoinTokenSuspender([ResourceKind.Server]);
// Starts resource querying interval.
const { result, active } = usePingTeleport<Node>(joinToken);

Expand Down
Expand Up @@ -28,7 +28,7 @@ export function ServerWrapper(props: ServerWrapperProps) {
useEffect(() => {
return () => {
// once the user leaves the desktop setup flow, delete the existing token
clearCachedJoinTokenResult(ResourceKind.Server);
clearCachedJoinTokenResult([ResourceKind.Server]);
};
}, []);

Expand Down
5 changes: 5 additions & 0 deletions web/packages/teleport/src/Discover/Shared/ResourceKind.ts
Expand Up @@ -25,6 +25,7 @@ export enum ResourceKind {
Kubernetes,
Server,
SamlApplication,
Discovery,
}

export function resourceKindToJoinRole(kind: ResourceKind): JoinRole {
Expand All @@ -39,6 +40,8 @@ export function resourceKindToJoinRole(kind: ResourceKind): JoinRole {
return 'Kube';
case ResourceKind.Server:
return 'Node';
case ResourceKind.Discovery:
return 'Discovery';
}
}

Expand All @@ -56,5 +59,7 @@ export function resourceKindToPreferredResource(
return ClusterResource.RESOURCE_KUBERNETES;
case ResourceKind.Server:
return ClusterResource.RESOURCE_SERVER_SSH;
case ResourceKind.Discovery:
return ClusterResource.RESOURCE_UNSPECIFIED;
}
}
18 changes: 10 additions & 8 deletions web/packages/teleport/src/Discover/Shared/useJoinTokenSuspender.ts
Expand Up @@ -35,14 +35,14 @@ interface SuspendResult {
}

let abortController: AbortController;
let joinTokenCache = new Map<ResourceKind, SuspendResult>();
let joinTokenCache = new Map<string, SuspendResult>();

export function clearCachedJoinTokenResult(resourceKind: ResourceKind) {
joinTokenCache.delete(resourceKind);
export function clearCachedJoinTokenResult(resourceKinds: ResourceKind[]) {
joinTokenCache.delete(resourceKinds.sort().join());
}

export function useJoinTokenSuspender(
resourceKind: ResourceKind,
resourceKinds: ResourceKind[],
suggestedAgentMatcherLabels: AgentLabel[] = [],
joinMethod: JoinMethod = 'token'
): {
Expand All @@ -54,6 +54,8 @@ export function useJoinTokenSuspender(

const [, rerender] = useState(0);

const kindsKey = resourceKinds.sort().join();

function run() {
abortController = new AbortController();

Expand All @@ -63,7 +65,7 @@ export function useJoinTokenSuspender(
promise: ctx.joinTokenService
.fetchJoinToken(
{
roles: [resourceKindToJoinRole(resourceKind)],
roles: resourceKinds.map(resourceKindToJoinRole),
method: joinMethod,
suggestedAgentMatcherLabels,
},
Expand All @@ -85,7 +87,7 @@ export function useJoinTokenSuspender(
}),
};

joinTokenCache.set(resourceKind, result);
joinTokenCache.set(kindsKey, result);

return result;
}
Expand All @@ -96,7 +98,7 @@ export function useJoinTokenSuspender(
};
}, []);

const existing = joinTokenCache.get(resourceKind);
const existing = joinTokenCache.get(kindsKey);

if (existing) {
if (existing.error) {
Expand All @@ -110,7 +112,7 @@ export function useJoinTokenSuspender(
// Delete the cached token and force a rerender
// so that this hook runs again and creates a new one.

joinTokenCache.delete(resourceKind);
joinTokenCache.delete(kindsKey);

rerender(c => c + 1);
},
Expand Down
9 changes: 8 additions & 1 deletion web/packages/teleport/src/services/joinToken/types.ts
Expand Up @@ -38,7 +38,14 @@ export type JoinToken = {
// - 'Kube' is a role for a kube service
// - 'Node' is a role for a node in the cluster
// - 'WindowsDesktop' is a role for a windows desktop service.
export type JoinRole = 'App' | 'Node' | 'Db' | 'Kube' | 'WindowsDesktop';
// - 'Discovery' is a role for a discovery service.
export type JoinRole =
| 'App'
| 'Node'
| 'Db'
| 'Kube'
| 'WindowsDesktop'
| 'Discovery';

// JoinMethod is the method used for new nodes to join the cluster.
// Same hard-corded value as the backend.
Expand Down

0 comments on commit 9617ecf

Please sign in to comment.