diff --git a/packages/manager/.changeset/pr-10868-upcoming-features-1725546685590.md b/packages/manager/.changeset/pr-10868-upcoming-features-1725546685590.md
new file mode 100644
index 00000000000..8677ed9acc1
--- /dev/null
+++ b/packages/manager/.changeset/pr-10868-upcoming-features-1725546685590.md
@@ -0,0 +1,5 @@
+---
+"@linode/manager": Upcoming Features
+---
+
+Add conditional client library update required reboot notice to Volume Create page ([#10868](https://github.com/linode/manager/pull/10868))
diff --git a/packages/manager/cypress/e2e/core/volumes/create-volume.spec.ts b/packages/manager/cypress/e2e/core/volumes/create-volume.spec.ts
index 6dfd3bc07dd..654bfa0ddb2 100644
--- a/packages/manager/cypress/e2e/core/volumes/create-volume.spec.ts
+++ b/packages/manager/cypress/e2e/core/volumes/create-volume.spec.ts
@@ -1,6 +1,9 @@
import type { Linode, Region } from '@linode/api-v4';
import { createTestLinode } from 'support/util/linodes';
-import { createLinodeRequestFactory } from 'src/factories/linodes';
+import {
+ createLinodeRequestFactory,
+ linodeFactory,
+} from 'src/factories/linodes';
import { authenticate } from 'support/api/authentication';
import { cleanUp } from 'support/util/cleanup';
import {
@@ -15,6 +18,10 @@ import { mockAppendFeatureFlags } from 'support/intercepts/feature-flags';
import { accountFactory, regionFactory, volumeFactory } from 'src/factories';
import { mockGetAccount } from 'support/intercepts/account';
import { mockGetRegions } from 'support/intercepts/regions';
+import {
+ mockGetLinodeDetails,
+ mockGetLinodes,
+} from 'support/intercepts/linodes';
// Local storage override to force volume table to list up to 100 items.
// This is a workaround while we wait to get stuck volumes removed.
@@ -132,6 +139,10 @@ describe('volume create flow', () => {
.should('be.visible')
.click();
+ // @TODO BSE: once BSE is fully rolled out, check for the notice (selected linode doesn't have
+ // blockstorage_encryption capability + user checked "Encrypt Volume" checkbox) instead of the absence of it
+ cy.findByText(CLIENT_LIBRARY_UPDATE_COPY).should('not.exist');
+
cy.findByText('Create Volume').click();
cy.wait('@createVolume');
@@ -162,7 +173,112 @@ describe('volume create flow', () => {
});
/*
- * - Checks for Block Storage Encryption notices in the Create/Attach Volume drawer from the
+ * - Checks for Block Storage Encryption client library update notice on the Volume Create page.
+ */
+ it('displays a warning notice on Volume Create page re: rebooting for client library updates under the appropriate conditions', () => {
+ // Conditions: Block Storage encryption feature flag is on; user has Block Storage Encryption capability; volume being created is encrypted and the
+ // selected Linode does not support Block Storage Encryption
+
+ // Mock feature flag -- @TODO BSE: Remove feature flag once BSE is fully rolled out
+ mockAppendFeatureFlags({
+ blockStorageEncryption: true,
+ }).as('getFeatureFlags');
+
+ // Mock account response
+ const mockAccount = accountFactory.build({
+ capabilities: ['Linodes', 'Block Storage Encryption'],
+ });
+
+ mockGetAccount(mockAccount).as('getAccount');
+ mockGetRegions(mockRegions).as('getRegions');
+
+ const linodeRequest = createLinodeRequestFactory.build({
+ label: randomLabel(),
+ root_pass: randomString(16),
+ region: mockRegions[0].id,
+ booted: false,
+ });
+
+ cy.defer(() => createTestLinode(linodeRequest), 'creating Linode').then(
+ (linode: Linode) => {
+ cy.visitWithLogin('/volumes/create');
+ cy.wait(['@getFeatureFlags', '@getAccount']);
+
+ // Select a linode without the BSE capability
+ cy.findByLabelText('Linode')
+ .should('be.visible')
+ .click()
+ .type(linode.label);
+
+ ui.autocompletePopper
+ .findByTitle(linode.label)
+ .should('be.visible')
+ .click();
+
+ // Check the "Encrypt Volume" checkbox
+ cy.get('[data-qa-checked]').should('be.visible').click();
+ // });
+
+ // Ensure warning notice is displayed
+ cy.findByText(CLIENT_LIBRARY_UPDATE_COPY).should('be.visible');
+ }
+ );
+ });
+
+ /*
+ * - Checks for absence of Block Storage Encryption client library update notice on the Volume Create page
+ * when selected linode supports BSE
+ */
+ it('does not display a warning notice on Volume Create page re: rebooting for client library updates when selected linode supports BSE', () => {
+ // Conditions: Block Storage encryption feature flag is on; user has Block Storage Encryption capability; volume being created is encrypted and the
+ // selected Linode supports Block Storage Encryption
+
+ // Mock feature flag -- @TODO BSE: Remove feature flag once BSE is fully rolled out
+ mockAppendFeatureFlags({
+ blockStorageEncryption: true,
+ }).as('getFeatureFlags');
+
+ // Mock account response
+ const mockAccount = accountFactory.build({
+ capabilities: ['Linodes', 'Block Storage Encryption'],
+ });
+
+ // Mock linode
+ const mockLinode = linodeFactory.build({
+ region: mockRegions[0].id,
+ id: 123456,
+ capabilities: ['blockstorage_encryption'],
+ });
+
+ mockGetAccount(mockAccount).as('getAccount');
+ mockGetRegions(mockRegions).as('getRegions');
+ mockGetLinodes([mockLinode]).as('getLinodes');
+ mockGetLinodeDetails(mockLinode.id, mockLinode);
+
+ cy.visitWithLogin(`/volumes/create`);
+ cy.wait(['@getAccount', '@getRegions', '@getLinodes']);
+
+ // Select a linode without the BSE capability
+ cy.findByLabelText('Linode')
+ .should('be.visible')
+ .click()
+ .type(mockLinode.label);
+
+ ui.autocompletePopper
+ .findByTitle(mockLinode.label)
+ .should('be.visible')
+ .click();
+
+ // Check the "Encrypt Volume" checkbox
+ cy.get('[data-qa-checked]').should('be.visible').click();
+ // });
+
+ // Ensure warning notice is not displayed
+ cy.findByText(CLIENT_LIBRARY_UPDATE_COPY).should('not.exist');
+ });
+
+ /*
+ * - Checks for Block Storage Encryption client library update notice in the Create/Attach Volume drawer from the
'Storage' details page of an existing Linode.
*/
it('displays a warning notice re: rebooting for client library updates under the appropriate conditions', () => {
diff --git a/packages/manager/src/features/Volumes/VolumeCreate.tsx b/packages/manager/src/features/Volumes/VolumeCreate.tsx
index 464c91f3e28..d1f4de80ca2 100644
--- a/packages/manager/src/features/Volumes/VolumeCreate.tsx
+++ b/packages/manager/src/features/Volumes/VolumeCreate.tsx
@@ -11,6 +11,7 @@ import { Button } from 'src/components/Button/Button';
import { DocumentTitleSegment } from 'src/components/DocumentTitle';
import {
BLOCK_STORAGE_CHOOSE_REGION_COPY,
+ BLOCK_STORAGE_CLIENT_LIBRARY_UPDATE_REQUIRED_COPY,
BLOCK_STORAGE_ENCRYPTION_GENERAL_DESCRIPTION,
BLOCK_STORAGE_ENCRYPTION_OVERHEAD_CAVEAT,
BLOCK_STORAGE_ENCRYPTION_UNAVAILABLE_IN_REGION_COPY,
@@ -23,6 +24,7 @@ import { LandingHeader } from 'src/components/LandingHeader';
import { Notice } from 'src/components/Notice/Notice';
import { Paper } from 'src/components/Paper';
import { RegionSelect } from 'src/components/RegionSelect/RegionSelect';
+import { Stack } from 'src/components/Stack';
import { TextField } from 'src/components/TextField';
import { TooltipIcon } from 'src/components/TooltipIcon';
import { Typography } from 'src/components/Typography';
@@ -35,6 +37,7 @@ import {
useAccountAgreements,
useMutateAccountAgreements,
} from 'src/queries/account/agreements';
+import { useLinodeQuery } from 'src/queries/linodes/linodes';
import { useGrants, useProfile } from 'src/queries/profile/profile';
import { useRegionsQuery } from 'src/queries/regions/regions';
import {
@@ -240,6 +243,15 @@ export const VolumeCreate = () => {
const { config_id, linode_id } = values;
+ const { data: linode } = useLinodeQuery(
+ linode_id ?? -1,
+ isBlockStorageEncryptionFeatureEnabled
+ );
+
+ const linodeSupportsBlockStorageEncryption = Boolean(
+ linode?.capabilities?.includes('blockstorage_encryption')
+ );
+
const linodeError = touched.linode_id ? errors.linode_id : undefined;
const { showGDPRCheckbox } = getGDPRDetails({
@@ -283,6 +295,11 @@ export const VolumeCreate = () => {
}
};
+ const shouldDisplayClientLibraryCopy =
+ isBlockStorageEncryptionFeatureEnabled &&
+ values.linode_id !== null &&
+ !linodeSupportsBlockStorageEncryption;
+
return (
<>
@@ -363,47 +380,57 @@ export const VolumeCreate = () => {
)}
-
- {
- const linodeRegion = linode.region;
- const valuesRegion = values.region;
-
- /** When values.region is empty, all Linodes with
- * block storage support will be displayed, regardless
- * of their region. However, if a region is selected,
- * only Linodes from the chosen region with block storage
- * support will be shown. */
- return isNilOrEmpty(valuesRegion)
- ? regionsWithBlockStorage.includes(linodeRegion)
- : regionsWithBlockStorage.includes(linodeRegion) &&
- linodeRegion === valuesRegion;
- }}
- sx={{
- [theme.breakpoints.down('sm')]: {
- width: 320,
- },
- width: '400px',
- }}
- clearable
- disabled={doesNotHavePermission}
- errorText={linodeError}
- onBlur={handleBlur}
- onSelectionChange={handleLinodeChange}
- value={values.linode_id}
- />
- {renderSelectTooltip(
- 'If you select a Linode, the Volume will be automatically created in that Linode’s region and attached upon creation.'
- )}
-
+
+
+ {
+ const linodeRegion = linode.region;
+ const valuesRegion = values.region;
+
+ /** When values.region is empty, all Linodes with
+ * block storage support will be displayed, regardless
+ * of their region. However, if a region is selected,
+ * only Linodes from the chosen region with block storage
+ * support will be shown. */
+ return isNilOrEmpty(valuesRegion)
+ ? regionsWithBlockStorage.includes(linodeRegion)
+ : regionsWithBlockStorage.includes(linodeRegion) &&
+ linodeRegion === valuesRegion;
+ }}
+ sx={{
+ [theme.breakpoints.down('sm')]: {
+ width: 320,
+ },
+ width: '400px',
+ }}
+ clearable
+ disabled={doesNotHavePermission}
+ errorText={linodeError}
+ onBlur={handleBlur}
+ onSelectionChange={handleLinodeChange}
+ value={values.linode_id}
+ />
+ {renderSelectTooltip(
+ 'If you select a Linode, the Volume will be automatically created in that Linode’s region and attached upon creation.'
+ )}
+
+ {shouldDisplayClientLibraryCopy &&
+ values.encryption === 'enabled' && (
+
+
+ {BLOCK_STORAGE_CLIENT_LIBRARY_UPDATE_REQUIRED_COPY}
+
+
+ )}
+
{