diff --git a/src/bucket.ts b/src/bucket.ts index d4321e072..7ea33e957 100644 --- a/src/bucket.ts +++ b/src/bucket.ts @@ -308,6 +308,9 @@ export interface BucketMetadata extends BaseMetadata { encryption?: { defaultKmsKeyName?: string; } | null; + hierarchicalNamespace?: { + enabled?: boolean; + }; iamConfiguration?: { publicAccessPrevention?: string; uniformBucketLevelAccess?: { diff --git a/src/storage.ts b/src/storage.ts index f13c37acc..a7027bc83 100644 --- a/src/storage.ts +++ b/src/storage.ts @@ -124,6 +124,16 @@ export interface CreateBucketRequest { customPlacementConfig?: CustomPlacementConfig; dra?: boolean; enableObjectRetention?: boolean; + hierarchicalNamespace?: { + enabled?: boolean; + }; + iamConfiguration?: { + publicAccessPrevention?: string; + uniformBucketLevelAccess?: { + enabled?: boolean; + lockedTime?: string; + }; + }; location?: string; multiRegional?: boolean; nearline?: boolean; @@ -868,6 +878,7 @@ export class Storage extends Service { * @property {boolean} [dra=false] Specify the storage class as Durable Reduced * Availability. * @property {boolean} [enableObjectRetention=false] Specifiy whether or not object retention should be enabled on this bucket. + * @property {object} [hierarchicalNamespace.enabled=false] Specify whether or not to enable hierarchical namespace on this bucket. * @property {string} [location] Specify the bucket's location. If specifying * a dual-region, the `customPlacementConfig` property should be set in conjunction. * For more information, see {@link https://cloud.google.com/storage/docs/locations| Bucket Locations}. diff --git a/system-test/storage.ts b/system-test/storage.ts index 5bee90e5e..cd184f4bc 100644 --- a/system-test/storage.ts +++ b/system-test/storage.ts @@ -1512,6 +1512,50 @@ describe('storage', function () { }); }); + describe('bucket hierarchical namespace', async () => { + let bucket: Bucket; + + beforeEach(() => { + bucket = storage.bucket(generateName()); + }); + + afterEach(async () => { + try { + await bucket.delete(); + } catch { + //Ignore errors + } + }); + + it('should create a bucket without hierarchical namespace enabled (implicit)', async () => { + await storage.createBucket(bucket.name); + const [metadata] = await bucket.getMetadata(); + assert.strictEqual(metadata.hierarchicalNamespace, undefined); + }); + + it('should create a bucket without hierarchical namespace enabled (explicit)', async () => { + await storage.createBucket(bucket.name, { + hierarchicalNamespace: {enabled: false}, + }); + const [metadata] = await bucket.getMetadata(); + assert.strictEqual(metadata.hierarchicalNamespace, undefined); + }); + + it('should create a bucket with hierarchical namespace enabled', async () => { + await storage.createBucket(bucket.name, { + hierarchicalNamespace: {enabled: true}, + iamConfiguration: { + uniformBucketLevelAccess: { + enabled: true, + }, + }, + }); + const [metadata] = await bucket.getMetadata(); + assert(metadata.hierarchicalNamespace); + assert.strictEqual(metadata.hierarchicalNamespace.enabled, true); + }); + }); + describe('bucket retention policies', () => { describe('bucket', () => { it('should create a bucket with a retention policy', async () => { diff --git a/test/index.ts b/test/index.ts index e09814ad6..72637a466 100644 --- a/test/index.ts +++ b/test/index.ts @@ -923,6 +923,21 @@ describe('Storage', () => { storage.createBucket(BUCKET_NAME, {enableObjectRetention: true}, done); }); + it('should allow enabling hierarchical namespace', done => { + storage.request = ( + reqOpts: DecorateRequestOptions, + callback: Function + ) => { + assert.strictEqual(reqOpts.json.hierarchicalNamespace.enabled, true); + callback(); + }; + storage.createBucket( + BUCKET_NAME, + {hierarchicalNamespace: {enabled: true}}, + done + ); + }); + describe('storage classes', () => { it('should expand metadata.archive', done => { storage.request = (reqOpts: DecorateRequestOptions) => {