Skip to content
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

upcoming: [M3-8019] – Add Encrypted/Not Encrypted status to Linode Detail summary header #10537

Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be an Added changeset?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

From my perspective, for the api-v4 package, "Added" indicates a newly-created type or interface, whereas "Changed" would include existing types and interfaces being expanded with new properties. Open to changing this based on additional thoughts, but it's probably a good Cafe item so a convention can be set.

Copy link
Contributor

Choose a reason for hiding this comment

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

Your perspective makes sense - I am curious to hear what other members of the team think fits best here. Totally possible that I'm just thinking about it differently.

Copy link
Contributor

Choose a reason for hiding this comment

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

(In support of leaving this changeset as is, I can add a comment to our next changelog doc when the team reviews pre-release just to clarify our convention, and we won't need to dedicate any cafe time.)

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/api-v4": Changed
---

Add lke_cluster_id to Linode interface ([#10537](https://github.com/linode/manager/pull/10537))
1 change: 1 addition & 0 deletions packages/api-v4/src/linodes/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export interface Linode {
ipv4: string[];
ipv6: string | null;
label: string;
lke_cluster_id: number | null;
placement_group?: PlacementGroupPayload; // If not in a placement group, this will be excluded from the response.
type: string | null;
status: LinodeStatus;
Expand Down
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-10537-added-1717182633416.md
dwiley-akamai marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Added
---

Add Encrypted / Not Encrypted status to Linode Detail header ([#10537](https://github.com/linode/manager/pull/10537))
4 changes: 4 additions & 0 deletions packages/manager/src/__data__/linodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const linode1: Linode = {
ipv4: ['97.107.143.78', '98.107.143.78', '99.107.143.78'],
ipv6: '2600:3c03::f03c:91ff:fe0a:109a/64',
label: 'test',
lke_cluster_id: null,
placement_group: {
affinity_type: 'anti_affinity:local',
id: 1,
Expand Down Expand Up @@ -69,6 +70,7 @@ export const linode2: Linode = {
ipv4: ['97.107.143.49'],
ipv6: '2600:3c03::f03c:91ff:fe0a:0d7a/64',
label: 'another-test',
lke_cluster_id: null,
placement_group: {
affinity_type: 'anti_affinity:local',
id: 1,
Expand Down Expand Up @@ -114,6 +116,7 @@ export const linode3: Linode = {
ipv4: ['97.107.143.49'],
ipv6: '2600:3c03::f03c:91ff:fe0a:0d7a/64',
label: 'another-test',
lke_cluster_id: null,
placement_group: {
affinity_type: 'anti_affinity:local',
id: 1,
Expand Down Expand Up @@ -159,6 +162,7 @@ export const linode4: Linode = {
ipv4: ['97.107.143.49'],
ipv6: '2600:3c03::f03c:91ff:fe0a:0d7a/64',
label: 'another-test-eu',
lke_cluster_id: null,
placement_group: {
affinity_type: 'anti_affinity:local',
id: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,9 @@ export const DISK_ENCRYPTION_BACKUPS_CAVEAT_COPY =

export const DISK_ENCRYPTION_NODE_POOL_GUIDANCE_COPY =
'To enable disk encryption, delete the node pool and create a new node pool. New node pools are always encrypted.';

export const UNENCRYPTED_STANDARD_LINODE_GUIDANCE_COPY =
'Use Rebuild to enable or disable disk encryption.';
Copy link
Contributor

Choose a reason for hiding this comment

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

This copy feels a little strange when it begins with the two verbs next to each other. Would something like Rebuild your Linode to enable or disable disk encryption. be better here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will bring this to UX for consideration πŸ‘€

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Revised to Rebuild this Linode to enable or disable disk encryption. after revisiting the copy with UX πŸš€


export const UNENCRYPTED_LKE_LINODE_GUIDANCE_COPY =
mjac0bs marked this conversation as resolved.
Show resolved Hide resolved
'To enable disk encryption, delete the node pool and create a new node pool. New node pools are always encrypted.';
1 change: 1 addition & 0 deletions packages/manager/src/factories/linodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ export const linodeFactory = Factory.Sync.makeFactory<Linode>({
ipv4: ['50.116.6.212', '192.168.203.1'],
ipv6: '2600:3c00::f03c:92ff:fee2:6c40/64',
label: Factory.each((i) => `linode-${i}`),
lke_cluster_id: null,
placement_group: placementGroupFactory.build({
affinity_type: 'anti_affinity:local',
id: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,10 @@ export const EncryptedStatus = ({
</>
) : encryptionStatus === 'disabled' ? (
<>
<Unlock />
<StyledTypography>Not Encrypted</StyledTypography>
<Unlock style={{ minWidth: 16 }} />
<StyledTypography sx={{ whiteSpace: 'nowrap' }}>
Not Encrypted
</StyledTypography>
{tooltipText ? <TooltipIcon status="help" text={tooltipText} /> : null}
</>
) : null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { HttpResponse, http, server } from 'src/mocks/testServer';
import { queryClientFactory } from 'src/queries/base';
import { mockMatchMedia, renderWithTheme } from 'src/utilities/testHelpers';

import { encryptionStatusTestId } from '../Kubernetes/KubernetesClusterDetail/NodePoolsDisplay/NodeTable';
import { LinodeEntityDetail } from './LinodeEntityDetail';
import { getSubnetsString } from './LinodeEntityDetailBody';
import { LinodeHandlers } from './LinodesLanding/LinodesLanding';
Expand All @@ -34,6 +35,29 @@ describe('Linode Entity Detail', () => {
const vpcSectionTestId = 'vpc-section-title';
const assignedVPCLabelTestId = 'assigned-vpc-label';

const mocks = vi.hoisted(() => {
return {
useIsDiskEncryptionFeatureEnabled: vi.fn(),
};
});

vi.mock('src/components/DiskEncryption/utils.ts', async () => {
const actual = await vi.importActual<any>(
'src/components/DiskEncryption/utils.ts'
);
return {
...actual,
__esModule: true,
useIsDiskEncryptionFeatureEnabled: mocks.useIsDiskEncryptionFeatureEnabled.mockImplementation(
() => {
return {
isDiskEncryptionFeatureEnabled: false, // indicates the feature flag is off or account capability is absent
};
}
),
};
});

it('should not display the VPC section if the linode is not assigned to a VPC', async () => {
const account = accountFactory.build({
capabilities: [...accountCapabilitiesWithoutVPC, 'VPCs'],
Expand Down Expand Up @@ -104,6 +128,41 @@ describe('Linode Entity Detail', () => {
expect(getByTestId(assignedVPCLabelTestId).innerHTML).toEqual('test-vpc');
});
});

it('should not display the encryption status of the linode if the account lacks the capability or the feature flag is off', () => {
// situation where isDiskEncryptionFeatureEnabled === false
const { queryByTestId } = renderWithTheme(
<LinodeEntityDetail
handlers={handlers}
id={10}
linode={linode}
openTagDrawer={vi.fn()}
/>
);
const encryptionStatusFragment = queryByTestId(encryptionStatusTestId);

expect(encryptionStatusFragment).not.toBeInTheDocument();
});

it('should display the encryption status of the linode when Disk Encryption is enabled and the user has the account capability', () => {
mocks.useIsDiskEncryptionFeatureEnabled.mockImplementationOnce(() => {
return {
isDiskEncryptionFeatureEnabled: true,
};
});

const { queryByTestId } = renderWithTheme(
<LinodeEntityDetail
handlers={handlers}
id={10}
linode={linode}
openTagDrawer={vi.fn()}
/>
);
const encryptionStatusFragment = queryByTestId(encryptionStatusTestId);

expect(encryptionStatusFragment).toBeInTheDocument();
});
});

describe('getSubnetsString function', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,12 @@ export const LinodeEntityDetail = (props: Props) => {
body={
<LinodeEntityDetailBody
configInterfaceWithVPC={configInterfaceWithVPC}
encryptionStatus={linode.disk_encryption}
gbRAM={linode.specs.memory / 1024}
gbStorage={linode.specs.disk / 1024}
ipv4={linode.ipv4}
ipv6={trimmedIPv6}
isLKELinode={Boolean(linode.lke_cluster_id)}
isVPCOnlyLinode={isVPCOnlyLinode}
linodeId={linode.id}
linodeIsInEdgeRegion={linodeIsInEdgeRegion}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,20 @@ import Grid from '@mui/material/Unstable_Grid2';
import * as React from 'react';
import { HashLink } from 'react-router-hash-link';

import { Box } from 'src/components/Box';
import {
UNENCRYPTED_LKE_LINODE_GUIDANCE_COPY,
UNENCRYPTED_STANDARD_LINODE_GUIDANCE_COPY,
} from 'src/components/DiskEncryption/constants';
import { useIsDiskEncryptionFeatureEnabled } from 'src/components/DiskEncryption/utils';
import { Link } from 'src/components/Link';
import { Typography, TypographyProps } from 'src/components/Typography';
import { AccessTable } from 'src/features/Linodes/AccessTable';
import { useProfile } from 'src/queries/profile';
import { pluralize } from 'src/utilities/pluralize';

import { encryptionStatusTestId } from '../Kubernetes/KubernetesClusterDetail/NodePoolsDisplay/NodeTable';
import { EncryptedStatus } from '../Kubernetes/KubernetesClusterDetail/NodePoolsDisplay/NodeTable';
import {
StyledBodyGrid,
StyledColumnLabelGrid,
Expand All @@ -24,7 +32,11 @@ import { ipv4TableID } from './LinodesDetail/LinodeNetworking/LinodeIPAddresses'
import { lishLink, sshLink } from './LinodesDetail/utilities';
import { LinodeHandlers } from './LinodesLanding/LinodesLanding';

import type { Interface, Linode } from '@linode/api-v4/lib/linodes/types';
import type {
EncryptionStatus,
Interface,
Linode,
} from '@linode/api-v4/lib/linodes/types';
import type { Subnet } from '@linode/api-v4/lib/vpcs';

interface LinodeEntityDetailProps {
Expand All @@ -41,10 +53,12 @@ export interface Props extends LinodeEntityDetailProps {

export interface BodyProps {
configInterfaceWithVPC?: Interface;
encryptionStatus: EncryptionStatus | undefined;
gbRAM: number;
gbStorage: number;
ipv4: Linode['ipv4'];
ipv6: Linode['ipv6'];
isLKELinode: boolean; // indicates whether linode belongs to an LKE cluster
isVPCOnlyLinode: boolean;
linodeId: number;
linodeIsInEdgeRegion: boolean;
Expand All @@ -58,10 +72,12 @@ export interface BodyProps {
export const LinodeEntityDetailBody = React.memo((props: BodyProps) => {
const {
configInterfaceWithVPC,
encryptionStatus,
gbRAM,
gbStorage,
ipv4,
ipv6,
isLKELinode,
isVPCOnlyLinode,
linodeId,
linodeIsInEdgeRegion,
Expand All @@ -77,6 +93,14 @@ export const LinodeEntityDetailBody = React.memo((props: BodyProps) => {

const theme = useTheme();

const {
isDiskEncryptionFeatureEnabled,
} = useIsDiskEncryptionFeatureEnabled();

// @ TODO LDE: Remove usages of this variable once LDE is fully rolled out (being used to determine formatting adjustments currently)
const isDisplayingEncryptedStatus =
isDiskEncryptionFeatureEnabled && Boolean(encryptionStatus);

// Filter and retrieve subnets associated with a specific Linode ID
const linodeAssociatedSubnets = vpcLinodeIsAssignedTo?.subnets.filter(
(subnet) => subnet.linodes.some((linode) => linode.id === linodeId)
Expand All @@ -97,11 +121,14 @@ export const LinodeEntityDetailBody = React.memo((props: BodyProps) => {
<Grid
container
flexDirection={matchesLgUp ? 'row' : 'column'}
sm={3}
sm={isDisplayingEncryptedStatus ? 4 : 3}
spacing={0}
xs={12}
>
<StyledColumnLabelGrid mb={matchesLgUp ? 0 : 2} xs={12}>
<StyledColumnLabelGrid
mb={matchesLgUp && !isDisplayingEncryptedStatus ? 0 : 2}
xs={12}
>
Summary
</StyledColumnLabelGrid>
<StyledSummaryGrid container spacing={1}>
Expand All @@ -121,9 +148,28 @@ export const LinodeEntityDetailBody = React.memo((props: BodyProps) => {
{pluralize('Volume', 'Volumes', numVolumes)}
</Typography>
</Grid>
{isDiskEncryptionFeatureEnabled && encryptionStatus && (
<Grid>
<Box
alignItems="center"
data-testid={encryptionStatusTestId}
display="flex"
flexDirection="row"
>
<EncryptedStatus
tooltipText={
isLKELinode
? UNENCRYPTED_LKE_LINODE_GUIDANCE_COPY
: UNENCRYPTED_STANDARD_LINODE_GUIDANCE_COPY
}
encryptionStatus={encryptionStatus}
/>
</Box>
</Grid>
)}
</StyledSummaryGrid>
</Grid>
<Grid container sm={9} xs={12}>
<Grid container sm={isDisplayingEncryptedStatus ? 8 : 9} xs={12}>
<Grid container xs={12}>
<AccessTable
footer={
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const props: AddonsPanelProps = {
ipv4: ['45.56.75.98'],
ipv6: '2600:3c00::f03c:93ff:fe85:576d/128',
label: 'test_instance',
lke_cluster_id: null,
placement_group: {
affinity_type: 'anti_affinity:local',
id: 1,
Expand Down Expand Up @@ -107,6 +108,7 @@ const props: AddonsPanelProps = {
ipv4: ['192.168.139.183', '139.144.17.202'],
ipv6: '2600:3c04::f03c:93ff:fe75:0612/128',
label: 'debian-ca-central',
lke_cluster_id: null,
placement_group: {
affinity_type: 'anti_affinity:local',
id: 1,
Expand Down Expand Up @@ -151,6 +153,7 @@ const props: AddonsPanelProps = {
ipv4: ['45.79.74.95'],
ipv6: '2600:3c01::f03c:93ff:fe75:e4f9/128',
label: 'almalinux-us-west',
lke_cluster_id: null,
placement_group: {
affinity_type: 'anti_affinity:local',
id: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ describe('LinodeRow', () => {
ipv6={linode.ipv6 || ''}
key={`linode-row-${1}`}
label={linode.label}
lke_cluster_id={linode.lke_cluster_id}
placement_group={linode.placement_group}
region={linode.region}
specs={linode.specs}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ export const ListView = (props: RenderLinodesProps) => {
ipv6={linode.ipv6 || ''}
key={`linode-row-${idx}`}
label={linode.label}
lke_cluster_id={linode.lke_cluster_id}
maintenance={linode.maintenance}
placement_group={linode.placement_group}
region={linode.region}
specs={linode.specs}
Expand All @@ -54,7 +56,6 @@ export const ListView = (props: RenderLinodesProps) => {
type={linode.type}
updated={linode.updated}
watchdog_enabled={linode.watchdog_enabled}
maintenance={linode.maintenance}
/>
))}
</>
Expand Down
Loading