diff --git a/.changeset/sixty-shoes-prove.md b/.changeset/sixty-shoes-prove.md new file mode 100644 index 0000000000..67a019f1ea --- /dev/null +++ b/.changeset/sixty-shoes-prove.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-kubernetes-backend': patch +'@backstage/plugin-kubernetes-react': patch +--- + +Make PodExecTerminal UI OptIn diff --git a/plugins/kubernetes-react/config.d.ts b/plugins/kubernetes-react/config.d.ts new file mode 100644 index 0000000000..d8f6ba8ca9 --- /dev/null +++ b/plugins/kubernetes-react/config.d.ts @@ -0,0 +1,31 @@ +import { PodExecTerminal } from './src/components/PodExecTerminal/PodExecTerminal'; +/* + * Copyright 2023 The Backstage Authors + * + * 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. + */ + +export interface Config { + kubernetes?: { + /** + * Pod Exec Terminal config + */ + podExecTerminal?: { + /** + * Enable `PodExecTerminal` UI feature + * @visibility frontend + */ + enable?: boolean; + }; + }; +} diff --git a/plugins/kubernetes-react/package.json b/plugins/kubernetes-react/package.json index 8389b4d2a9..d85cb7ba35 100644 --- a/plugins/kubernetes-react/package.json +++ b/plugins/kubernetes-react/package.json @@ -14,6 +14,7 @@ "role": "web-library" }, "sideEffects": false, + "configSchema": "config.d.ts", "scripts": { "start": "backstage-cli package start", "build": "backstage-cli package build", @@ -60,6 +61,7 @@ "msw": "^1.3.1" }, "files": [ - "dist" + "dist", + "config.d.ts" ] } diff --git a/plugins/kubernetes-react/src/components/Pods/PodDrawer/ContainerCard.tsx b/plugins/kubernetes-react/src/components/Pods/PodDrawer/ContainerCard.tsx index db70f92160..592a93e3ea 100644 --- a/plugins/kubernetes-react/src/components/Pods/PodDrawer/ContainerCard.tsx +++ b/plugins/kubernetes-react/src/components/Pods/PodDrawer/ContainerCard.tsx @@ -27,6 +27,7 @@ import { IContainer, IContainerStatus } from 'kubernetes-models/v1'; import { DateTime } from 'luxon'; import React from 'react'; +import { useIsPodExecTerminalEnabled } from '../../../hooks'; import { bytesToMiB, formatMillicores } from '../../../utils/resources'; import { PodExecTerminalDialog } from '../../PodExecTerminal/PodExecTerminalDialog'; import { ResourceUtilization } from '../../ResourceUtilization'; @@ -108,6 +109,8 @@ export const ContainerCard: React.FC = ({ containerStatus, containerMetrics, }: ContainerCardProps) => { + const isPodExecTerminalEnabled = useIsPodExecTerminalEnabled(); + // This should never be undefined if (containerSpec === undefined) { return error reading pod from cluster; @@ -228,12 +231,14 @@ export const ContainerCard: React.FC = ({ ...podScope, }} /> - + {isPodExecTerminalEnabled && ( + + )} ); diff --git a/plugins/kubernetes-react/src/hooks/index.ts b/plugins/kubernetes-react/src/hooks/index.ts index 141bc3815b..2bc519d69a 100644 --- a/plugins/kubernetes-react/src/hooks/index.ts +++ b/plugins/kubernetes-react/src/hooks/index.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +export * from './useIsPodExecTerminalEnabled'; export * from './useIsPodExecTerminalSupported'; export * from './useKubernetesObjects'; export * from './useCustomResources'; diff --git a/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalEnabled.test.tsx b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalEnabled.test.tsx new file mode 100644 index 0000000000..3faf81d9ae --- /dev/null +++ b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalEnabled.test.tsx @@ -0,0 +1,64 @@ +/* + * Copyright 2023 The Backstage Authors + * + * 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 { ConfigReader } from '@backstage/core-app-api'; +import { configApiRef } from '@backstage/core-plugin-api'; +import { TestApiProvider } from '@backstage/test-utils'; +import { renderHook } from '@testing-library/react'; +import { PropsWithChildren } from 'react'; +import React from 'react'; + +import { useIsPodExecTerminalEnabled } from './useIsPodExecTerminalEnabled'; + +describe('useIsPodExecTerminalEnabled', () => { + let isPodExecTerminalEnabled: boolean | undefined; + + const apiWrapper = ({ children }: PropsWithChildren) => ( + + {children} + + ); + + it.each([ + { + condition: 'missing config', + returnValue: undefined, + }, + { condition: 'disabled', returnValue: false }, + { + condition: 'enabled', + returnValue: true, + }, + ])('Should return $returnValue if $condition', async ({ returnValue }) => { + isPodExecTerminalEnabled = returnValue; + + const { result } = renderHook(() => useIsPodExecTerminalEnabled(), { + wrapper: apiWrapper, + }); + + expect(result.current).toEqual(returnValue); + }); +}); diff --git a/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalEnabled.ts b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalEnabled.ts new file mode 100644 index 0000000000..683b9b9a5a --- /dev/null +++ b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalEnabled.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2023 The Backstage Authors + * + * 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 { configApiRef, useApi } from '@backstage/core-plugin-api'; + +/** + * Check if conditions for a pod exec call through the proxy endpoint are met + * + * @internal + */ +export const useIsPodExecTerminalEnabled = (): boolean | undefined => { + const configApi = useApi(configApiRef); + + return configApi.getOptionalBoolean('kubernetes.podExecTerminal.enable'); +}; diff --git a/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.test.ts b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.test.ts index 93bfb6dd4d..c4df347c6f 100644 --- a/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.test.ts +++ b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.test.ts @@ -20,7 +20,7 @@ import { useIsPodExecTerminalSupported } from './useIsPodExecTerminalSupported'; jest.mock('@backstage/core-plugin-api'); -describe('useIsClusterShellEnabled', () => { +describe('useIsPodExecTerminalSupported', () => { let clusters: { authProvider: string }[] = []; beforeEach(() => { diff --git a/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.ts b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.ts index e881951059..2483bb9412 100644 --- a/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.ts +++ b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.ts @@ -15,6 +15,7 @@ */ import { useApi } from '@backstage/core-plugin-api'; import useAsync, { AsyncState } from 'react-use/lib/useAsync'; + import { kubernetesApiRef } from '../api/types'; /**