From 5f3b4461af43766b429cf3cf39152099ae31b8d2 Mon Sep 17 00:00:00 2001 From: Mahmoud Bahaa Date: Sat, 22 Apr 2023 04:07:17 +0200 Subject: [PATCH 1/4] * Added "@loki @Sql" to all test cases except 2 --- src/blob/errors/StorageError.ts | 2 + src/blob/errors/StorageErrorFactory.ts | 2 +- tests/blob/apis/appendblob.test.ts | 38 ++++---- tests/blob/apis/blob.test.ts | 22 ++--- tests/blob/apis/container.test.ts | 3 +- tests/blob/apis/pageblob.test.ts | 94 +++++++++---------- tests/blob/apis/service.test.ts | 4 +- tests/blob/blockblob.highlevel.test.ts | 6 +- tests/blob/handlers/AppendBlobHandler.test.ts | 14 +-- tests/blob/pagewithdelimiter.test.ts | 28 +++--- tests/blob/sas.test.ts | 23 ++--- tests/blob/specialnaming.test.ts | 21 +++++ tests/blob/utils.test.ts | 10 +- 13 files changed, 145 insertions(+), 122 deletions(-) diff --git a/src/blob/errors/StorageError.ts b/src/blob/errors/StorageError.ts index a1a24d899..c1b9bb884 100644 --- a/src/blob/errors/StorageError.ts +++ b/src/blob/errors/StorageError.ts @@ -12,6 +12,7 @@ export default class StorageError extends MiddlewareError { public readonly storageErrorCode: string; public readonly storageErrorMessage: string; public readonly storageRequestID: string; + public readonly storageAdditionalErrorMessages: { [key: string]: string }; /** * Creates an instance of StorageError. @@ -61,5 +62,6 @@ export default class StorageError extends MiddlewareError { this.storageErrorCode = storageErrorCode; this.storageErrorMessage = storageErrorMessage; this.storageRequestID = storageRequestID; + this.storageAdditionalErrorMessages = storageAdditionalErrorMessages; } } diff --git a/src/blob/errors/StorageErrorFactory.ts b/src/blob/errors/StorageErrorFactory.ts index 573fe45b6..8757009fd 100644 --- a/src/blob/errors/StorageErrorFactory.ts +++ b/src/blob/errors/StorageErrorFactory.ts @@ -736,7 +736,7 @@ export default class StorageErrorFactory { return new StorageError( 400, "InvalidResourceName", - `The specifed resource name contains invalid characters.`, + `The specified resource name contains invalid characters.`, contextID ); } diff --git a/tests/blob/apis/appendblob.test.ts b/tests/blob/apis/appendblob.test.ts index 10e38822b..e07fd98bb 100644 --- a/tests/blob/apis/appendblob.test.ts +++ b/tests/blob/apis/appendblob.test.ts @@ -68,7 +68,7 @@ describe("AppendBlobAPIs", () => { await containerClient.delete(); }); - it("Create append blob should work @loki", async () => { + it("Create append blob should work @loki @sql", async () => { await appendBlobClient.create(); const properties = await appendBlobClient.getProperties(); assert.deepStrictEqual(properties.blobType, "AppendBlob"); @@ -85,7 +85,7 @@ describe("AppendBlobAPIs", () => { assert.deepStrictEqual(properties.blobCommittedBlockCount, 0); }); - it("Create append blob override existing pageblob @loki", async () => { + it("Create append blob override existing pageblob @loki @sql", async () => { const pageBlobClient = blobClient.getPageBlobClient(); await pageBlobClient.create(512); @@ -133,12 +133,12 @@ describe("AppendBlobAPIs", () => { assert.deepStrictEqual(properties.blobCommittedBlockCount, 0); }); - it("Delete append blob should work @loki", async () => { + it("Delete append blob should work @loki @sql", async () => { await appendBlobClient.create(); await appendBlobClient.delete(); }); - it("Create append blob snapshot should work @loki", async () => { + it("Create append blob snapshot should work @loki @sql", async () => { await appendBlobClient.create(); const response = await appendBlobClient.createSnapshot(); const appendBlobSnapshotClient = appendBlobClient.withSnapshot( @@ -176,7 +176,7 @@ describe("AppendBlobAPIs", () => { assert.deepStrictEqual(properties.blobCommittedBlockCount, 0); }); - it("Copy append blob snapshot should work @loki", async () => { + it("Copy append blob snapshot should work @loki @sql", async () => { await appendBlobClient.create(); await appendBlobClient.appendBlock("hello", 5); @@ -212,7 +212,7 @@ describe("AppendBlobAPIs", () => { assert.deepStrictEqual(properties.copyStatus, "success"); }); - it("Synchronized copy append blob snapshot should work @loki", async () => { + it("Synchronized copy append blob snapshot should work @loki @sql", async () => { await appendBlobClient.create(); await appendBlobClient.appendBlock("hello", 5); @@ -247,7 +247,7 @@ describe("AppendBlobAPIs", () => { assert.deepStrictEqual(properties.copySource, appendBlobSnapshotClient.url); }); - it("Set append blob metadata should work @loki", async () => { + it("Set append blob metadata should work @loki @sql", async () => { await appendBlobClient.create(); const metadata = { @@ -260,7 +260,7 @@ describe("AppendBlobAPIs", () => { assert.deepStrictEqual(properties.metadata, metadata); }); - it("Set append blob HTTP headers should work @loki", async () => { + it("Set append blob HTTP headers should work @loki @sql", async () => { await appendBlobClient.create(); const md5 = new Uint8Array([1, 2, 3, 4, 5]); @@ -292,7 +292,7 @@ describe("AppendBlobAPIs", () => { ); }); - it("Set tier should not work for append blob @loki", async function () { + it("Set tier should not work for append blob @loki @sql", async function () { await appendBlobClient.create(); try { await blobClient.setAccessTier("hot"); @@ -302,7 +302,7 @@ describe("AppendBlobAPIs", () => { assert.fail(); }); - it("Append block should work @loki", async () => { + it("Append block should work @loki @sql", async () => { await appendBlobClient.create(); let appendBlockResponse = await appendBlobClient.appendBlock("abcdef", 6); assert.deepStrictEqual(appendBlockResponse.blobAppendOffset, "0"); @@ -357,7 +357,7 @@ describe("AppendBlobAPIs", () => { assert.deepStrictEqual(string, "abcdef123456T@"); }); - it("Download append blob should work @loki", async () => { + it("Download append blob should work @loki @sql", async () => { await appendBlobClient.create(); await appendBlobClient.appendBlock("abcdef", 6); await appendBlobClient.appendBlock("123456", 6); @@ -374,7 +374,7 @@ describe("AppendBlobAPIs", () => { assert.deepStrictEqual(response.contentRange, "bytes 5-12/14"); }); - it("Download append blob should work for snapshot @loki", async () => { + it("Download append blob should work for snapshot @loki @sql", async () => { await appendBlobClient.create(); await appendBlobClient.appendBlock("abcdef", 6); @@ -393,7 +393,7 @@ describe("AppendBlobAPIs", () => { assert.deepEqual(response.contentMD5, await getMD5FromString("def")); }); - it("Download append blob should work for copied blob @loki", async () => { + it("Download append blob should work for copied blob @loki @sql", async () => { await appendBlobClient.create(); await appendBlobClient.appendBlock("abcdef", 6); @@ -410,7 +410,7 @@ describe("AppendBlobAPIs", () => { assert.deepEqual(response.contentMD5, await getMD5FromString("def")); }); - it("Append block with invalid blob type should not work @loki", async () => { + it("Append block with invalid blob type should not work @loki @sql", async () => { const pageBlobClient = appendBlobClient.getPageBlobClient(); await pageBlobClient.create(512); @@ -423,7 +423,7 @@ describe("AppendBlobAPIs", () => { assert.fail(); }); - it("Append block with content length 0 should not work @loki", async () => { + it("Append block with content length 0 should not work @loki @sql", async () => { await appendBlobClient.create(); try { @@ -435,7 +435,7 @@ describe("AppendBlobAPIs", () => { assert.fail(); }); - it("Append block append position access condition should work @loki", async () => { + it("Append block append position access condition should work @loki @sql", async () => { await appendBlobClient.create(); await appendBlobClient.appendBlock("a", 1, { conditions: { @@ -480,7 +480,7 @@ describe("AppendBlobAPIs", () => { assert.fail(); }); - it("Append block md5 validation should work @loki", async () => { + it("Append block md5 validation should work @loki @sql", async () => { await appendBlobClient.create(); await appendBlobClient.appendBlock("aEf", 1, { transactionalContentMD5: await getMD5FromString("aEf") @@ -498,7 +498,7 @@ describe("AppendBlobAPIs", () => { assert.fail(); }); - it("Append block access condition should work @loki", async () => { + it("Append block access condition should work @loki @sql", async () => { let response = await appendBlobClient.create(); response = await appendBlobClient.appendBlock("a", 1, { conditions: { @@ -538,7 +538,7 @@ describe("AppendBlobAPIs", () => { assert.fail(); }); - it("Append block lease condition should work @loki", async () => { + it("Append block lease condition should work @loki @sql", async () => { await appendBlobClient.create(); const leaseId = "abcdefg"; diff --git a/tests/blob/apis/blob.test.ts b/tests/blob/apis/blob.test.ts index 2e80a2a00..62ceee0ff 100644 --- a/tests/blob/apis/blob.test.ts +++ b/tests/blob/apis/blob.test.ts @@ -833,7 +833,7 @@ describe("BlobAPIs", () => { ); }); - it("Copy blob should work @loki", async () => { + it("Copy blob should work @loki @sql", async () => { const sourceBlob = getUniqueName("blob"); const destBlob = getUniqueName("blob"); @@ -892,7 +892,7 @@ describe("BlobAPIs", () => { ); }); - it("Copy blob should work to override metadata @loki", async () => { + it("Copy blob should work to override metadata @loki @sql", async () => { const sourceBlob = getUniqueName("blob"); const destBlob = getUniqueName("blob"); @@ -916,7 +916,7 @@ describe("BlobAPIs", () => { assert.deepStrictEqual(result.metadata, metadata2); }); - it("Copy blob should work with source archive blob and accesstier header @loki, @sql", async () => { + it("Copy blob should work with source archive blob and accesstier header @loki @sql", async () => { const sourceBlob = getUniqueName("blob"); const destBlob = getUniqueName("blob"); @@ -951,7 +951,7 @@ describe("BlobAPIs", () => { assert.deepStrictEqual(result.accessTier, "Hot"); }); - it("Copy blob should not override destination Lease status @loki", async () => { + it("Copy blob should not override destination Lease status @loki @sql", async () => { const sourceBlob = getUniqueName("blob"); const destBlob = getUniqueName("blob"); @@ -986,7 +986,7 @@ describe("BlobAPIs", () => { await destLeaseClient.releaseLease(); }); - it("Copy blob should work for page blob @loki", async () => { + it("Copy blob should work for page blob @loki @sql", async () => { const sourceBlob = getUniqueName("blob"); const destBlob = getUniqueName("blob"); @@ -1045,7 +1045,7 @@ describe("BlobAPIs", () => { ); }); - it("Copy blob should not work for page blob and set tier @loki", async () => { + it("Copy blob should not work for page blob and set tier @loki @sql", async () => { const sourceBlob = getUniqueName("blob"); const destBlob = getUniqueName("blob"); @@ -1083,7 +1083,7 @@ describe("BlobAPIs", () => { assert.deepStrictEqual(err.statusCode, 400); }); - it("Copy blob should not work with ifNoneMatch * when dest exist @loki", async () => { + it("Copy blob should not work with ifNoneMatch * when dest exist @loki @sql", async () => { const sourceBlob = getUniqueName("blob"); const destBlob = getUniqueName("blob"); @@ -1154,7 +1154,7 @@ describe("BlobAPIs", () => { assert.fail(); }); - it("Synchronized copy blob should work @loki", async () => { + it("Synchronized copy blob should work @loki @sql", async () => { const sourceBlob = getUniqueName("blob"); const destBlob = getUniqueName("blob"); @@ -1212,7 +1212,7 @@ describe("BlobAPIs", () => { ); }); - it("Synchronized copy blob should work to override metadata @loki", async () => { + it("Synchronized copy blob should work to override metadata @loki @sql", async () => { const sourceBlob = getUniqueName("blob"); const destBlob = getUniqueName("blob"); @@ -1236,7 +1236,7 @@ describe("BlobAPIs", () => { assert.deepStrictEqual(result.metadata, metadata2); }); - it("Synchronized copy blob should not override destination Lease status @loki", async () => { + it("Synchronized copy blob should not override destination Lease status @loki @sql", async () => { const sourceBlob = getUniqueName("blob"); const destBlob = getUniqueName("blob"); @@ -1271,7 +1271,7 @@ describe("BlobAPIs", () => { await destLeaseClient.releaseLease(); }); - it("Synchronized copy blob should work for page blob @loki", async () => { + it("Synchronized copy blob should work for page blob @loki @sql", async () => { const sourceBlob = getUniqueName("blob"); const destBlob = getUniqueName("blob"); diff --git a/tests/blob/apis/container.test.ts b/tests/blob/apis/container.test.ts index 64cf39880..fdbeaba0a 100644 --- a/tests/blob/apis/container.test.ts +++ b/tests/blob/apis/container.test.ts @@ -563,8 +563,7 @@ describe("ContainerAPIs", () => { } }); - // TODO: azure/storage-blob 12.9.0 will fail on list uncimmited blob from container, will skip the case until this is fix in SDK or Azurite - it.skip("should only show uncommitted blobs in listBlobFlatSegment with uncommittedblobs option @loki @sql", async () => { + it("should only show uncommitted blobs in listBlobFlatSegment with uncommittedblobs option @loki @sql", async () => { const blobClient = containerClient.getBlobClient( getUniqueName("uncommittedblob") ); diff --git a/tests/blob/apis/pageblob.test.ts b/tests/blob/apis/pageblob.test.ts index 570cfef0e..09ab9793c 100644 --- a/tests/blob/apis/pageblob.test.ts +++ b/tests/blob/apis/pageblob.test.ts @@ -66,7 +66,7 @@ describe("PageBlobAPIs", () => { await containerClient.delete(); }); - it("create with default parameters @loki", async () => { + it("create with default parameters @loki @sql", async () => { const reuslt_create = await pageBlobClient.create(512); assert.equal( reuslt_create._response.request.headers.get("x-ms-client-request-id"), @@ -84,7 +84,7 @@ describe("PageBlobAPIs", () => { ); }); - it("create with all parameters set @loki", async () => { + it("create with all parameters set @loki @sql", async () => { const options = { blobHTTPHeaders: { blobCacheControl: "blobCacheControl", @@ -144,7 +144,7 @@ describe("PageBlobAPIs", () => { ); }); - it("download page blob with partial ranges @loki", async () => { + it("download page blob with partial ranges @loki @sql", async () => { const length = 512 * 10; await pageBlobClient.create(length); @@ -171,7 +171,7 @@ describe("PageBlobAPIs", () => { assert.deepStrictEqual(result._response.status, 206); }); - it("download page blob with no ranges uploaded @loki", async () => { + it("download page blob with no ranges uploaded @loki @sql", async () => { const length = 512 * 10; await pageBlobClient.create(length); @@ -194,7 +194,7 @@ describe("PageBlobAPIs", () => { ); }); - it("download page blob with no ranges uploaded after resize to bigger size @loki", async () => { + it("download page blob with no ranges uploaded after resize to bigger size @loki @sql", async () => { let length = 512 * 10; await pageBlobClient.create(length); @@ -237,7 +237,7 @@ describe("PageBlobAPIs", () => { ); }); - it("download page blob with no ranges uploaded after resize to smaller size @loki", async () => { + it("download page blob with no ranges uploaded after resize to smaller size @loki @sql", async () => { let length = 512 * 10; await pageBlobClient.create(length); @@ -268,7 +268,7 @@ describe("PageBlobAPIs", () => { ); }); - it("uploadPages @loki", async () => { + it("uploadPages @loki @sql", async () => { await pageBlobClient.create(1024); const result = await blobClient.download(0); @@ -292,7 +292,7 @@ describe("PageBlobAPIs", () => { assert.equal(await bodyToString(page2, 512), "b".repeat(512)); }); - it("uploadPages should work with sequence number conditions @loki", async () => { + it("uploadPages should work with sequence number conditions @loki @sql", async () => { await pageBlobClient.create(1024); await pageBlobClient.updateSequenceNumber( @@ -327,7 +327,7 @@ describe("PageBlobAPIs", () => { assert.equal(await bodyToString(page2, 512), "b".repeat(512)); }); - it("uploadPages should not work if ifSequenceNumberEqualTo doesn't match @loki", async () => { + it("uploadPages should not work if ifSequenceNumberEqualTo doesn't match @loki @sql", async () => { await pageBlobClient.create(1024); await pageBlobClient.updateSequenceNumber( @@ -349,7 +349,7 @@ describe("PageBlobAPIs", () => { assert.fail(); }); - it("uploadPages should not work if ifSequenceNumberLessThan doesn't match @loki", async () => { + it("uploadPages should not work if ifSequenceNumberLessThan doesn't match @loki @sql", async () => { await pageBlobClient.create(1024); await pageBlobClient.updateSequenceNumber( @@ -382,7 +382,7 @@ describe("PageBlobAPIs", () => { assert.fail(); }); - it("uploadPages should not work if ifSequenceNumberLessThanOrEqualTo doesn't match @loki", async () => { + it("uploadPages should not work if ifSequenceNumberLessThanOrEqualTo doesn't match @loki @sql", async () => { await pageBlobClient.create(1024); await pageBlobClient.updateSequenceNumber( @@ -410,7 +410,7 @@ describe("PageBlobAPIs", () => { assert.fail(); }); - it("uploadPages with sequential pages @loki", async () => { + it("uploadPages with sequential pages @loki @sql", async () => { const length = 512 * 3; await pageBlobClient.create(length); @@ -443,7 +443,7 @@ describe("PageBlobAPIs", () => { assert.deepStrictEqual(ranges.pageRange![2], { offset: 1024, count: 511 }); }); - it("uploadPages with one big page range @loki", async () => { + it("uploadPages with one big page range @loki @sql", async () => { const length = 512 * 3; await pageBlobClient.create(length); @@ -476,7 +476,7 @@ describe("PageBlobAPIs", () => { assert.deepStrictEqual(ranges.pageRange![0], { offset: 0, count: 1535 }); }); - it("uploadPages with non-sequential pages @loki", async () => { + it("uploadPages with non-sequential pages @loki @sql", async () => { const length = 512 * 5; await pageBlobClient.create(length); @@ -515,7 +515,7 @@ describe("PageBlobAPIs", () => { assert.deepStrictEqual(ranges.pageRange![1], { offset: 1536, count: 511 }); }); - it("uploadPages to internally override a sequential range @loki", async () => { + it("uploadPages to internally override a sequential range @loki @sql", async () => { const length = 512 * 3; await pageBlobClient.create(length); @@ -552,7 +552,7 @@ describe("PageBlobAPIs", () => { assert.deepStrictEqual(ranges.pageRange![2], { offset: 1024, count: 511 }); }); - it("uploadPages to internally right align override a sequential range @loki", async () => { + it("uploadPages to internally right align override a sequential range @loki @sql", async () => { const length = 512 * 3; await pageBlobClient.create(length); @@ -588,7 +588,7 @@ describe("PageBlobAPIs", () => { assert.deepStrictEqual(ranges.pageRange![1], { offset: 1024, count: 511 }); }); - it("uploadPages to internally left align override a sequential range @loki", async () => { + it("uploadPages to internally left align override a sequential range @loki @sql", async () => { const length = 512 * 3; await pageBlobClient.create(length); @@ -624,7 +624,7 @@ describe("PageBlobAPIs", () => { assert.deepStrictEqual(ranges.pageRange![1], { offset: 512, count: 1023 }); }); - it("uploadPages to totally override a sequential range @loki", async () => { + it("uploadPages to totally override a sequential range @loki @sql", async () => { const length = 512 * 5; await pageBlobClient.create(length); @@ -678,7 +678,7 @@ describe("PageBlobAPIs", () => { }); }); - it("uploadPages to left override a sequential range @loki", async () => { + it("uploadPages to left override a sequential range @loki @sql", async () => { const length = 512 * 5; await pageBlobClient.create(length); @@ -722,7 +722,7 @@ describe("PageBlobAPIs", () => { assert.deepStrictEqual(ranges.pageRange![1], { offset: 1024, count: 1023 }); }); - it("uploadPages to right override a sequential range @loki", async () => { + it("uploadPages to right override a sequential range @loki @sql", async () => { const length = 512 * 5; await pageBlobClient.create(length); @@ -772,7 +772,7 @@ describe("PageBlobAPIs", () => { }); }); - it("resize override a sequential range @loki", async () => { + it("resize override a sequential range @loki @sql", async () => { let length = 512 * 3; await pageBlobClient.create(length); @@ -815,7 +815,7 @@ describe("PageBlobAPIs", () => { }); }); - it("uploadPages to internally override a non-sequential range @loki", async () => { + it("uploadPages to internally override a non-sequential range @loki @sql", async () => { const length = 512 * 5; await pageBlobClient.create(length); @@ -867,7 +867,7 @@ describe("PageBlobAPIs", () => { }); }); - it("uploadPages to internally insert into a non-sequential range @loki", async () => { + it("uploadPages to internally insert into a non-sequential range @loki @sql", async () => { const length = 512 * 5; await pageBlobClient.create(length); @@ -919,7 +919,7 @@ describe("PageBlobAPIs", () => { }); }); - it("uploadPages to totally override a non-sequential range @loki", async () => { + it("uploadPages to totally override a non-sequential range @loki @sql", async () => { const length = 512 * 5; await pageBlobClient.create(length); @@ -963,7 +963,7 @@ describe("PageBlobAPIs", () => { }); }); - it("uploadPages to left override a non-sequential range @loki", async () => { + it("uploadPages to left override a non-sequential range @loki @sql", async () => { const length = 512 * 5; await pageBlobClient.create(length); @@ -1011,7 +1011,7 @@ describe("PageBlobAPIs", () => { }); }); - it("uploadPages to insert into a non-sequential range @loki", async () => { + it("uploadPages to insert into a non-sequential range @loki @sql", async () => { const length = 512 * 5; await pageBlobClient.create(length); @@ -1063,7 +1063,7 @@ describe("PageBlobAPIs", () => { }); }); - it("uploadPages to right override a non-sequential range @loki", async () => { + it("uploadPages to right override a non-sequential range @loki @sql", async () => { const length = 512 * 5; await pageBlobClient.create(length); @@ -1111,7 +1111,7 @@ describe("PageBlobAPIs", () => { }); }); - it("clearPages @loki", async () => { + it("clearPages @loki @sql", async () => { await pageBlobClient.create(1024); let result = await blobClient.download(0); assert.deepStrictEqual( @@ -1135,7 +1135,7 @@ describe("PageBlobAPIs", () => { ); }); - it("clearPages should work with sequence number conditions @loki", async () => { + it("clearPages should work with sequence number conditions @loki @sql", async () => { await pageBlobClient.create(1024); await pageBlobClient.clearPages(0, 512, { conditions: { @@ -1146,7 +1146,7 @@ describe("PageBlobAPIs", () => { }); }); - it("clearPages should not work with invalid ifSequenceNumberEqualTo @loki", async () => { + it("clearPages should not work with invalid ifSequenceNumberEqualTo @loki @sql", async () => { await pageBlobClient.create(1024); try { await pageBlobClient.clearPages(0, 512, { @@ -1161,7 +1161,7 @@ describe("PageBlobAPIs", () => { assert.fail(); }); - it("clearPages should not work with invalid ifSequenceNumberLessThan @loki", async () => { + it("clearPages should not work with invalid ifSequenceNumberLessThan @loki @sql", async () => { await pageBlobClient.create(1024); await pageBlobClient.updateSequenceNumber( SequenceNumberActionType.Increment @@ -1186,7 +1186,7 @@ describe("PageBlobAPIs", () => { assert.fail(); }); - it("clearPages should not work with invalid ifSequenceNumberLessThanOrEqualTo @loki", async () => { + it("clearPages should not work with invalid ifSequenceNumberLessThanOrEqualTo @loki @sql", async () => { await pageBlobClient.create(1024); await pageBlobClient.updateSequenceNumber( SequenceNumberActionType.Increment @@ -1211,7 +1211,7 @@ describe("PageBlobAPIs", () => { assert.fail(); }); - it("clearPages to internally override a sequential range @loki", async () => { + it("clearPages to internally override a sequential range @loki @sql", async () => { const length = 512 * 5; await pageBlobClient.create(length); @@ -1261,7 +1261,7 @@ describe("PageBlobAPIs", () => { }); }); - it("clearPages to totally override a sequential range @loki", async () => { + it("clearPages to totally override a sequential range @loki @sql", async () => { const length = 512 * 5; await pageBlobClient.create(length); @@ -1303,7 +1303,7 @@ describe("PageBlobAPIs", () => { assert.deepStrictEqual((ranges.clearRange || []).length, 0); }); - it("clearPages to left override a sequential range @loki", async () => { + it("clearPages to left override a sequential range @loki @sql", async () => { const length = 512 * 5; await pageBlobClient.create(length); @@ -1349,7 +1349,7 @@ describe("PageBlobAPIs", () => { }); }); - it("clearPages to right override a sequential range @loki", async () => { + it("clearPages to right override a sequential range @loki @sql", async () => { const length = 512 * 5; await pageBlobClient.create(length); @@ -1395,7 +1395,7 @@ describe("PageBlobAPIs", () => { }); }); - it("clearPages to internally override a non-sequential range @loki", async () => { + it("clearPages to internally override a non-sequential range @loki @sql", async () => { const length = 512 * 5; await pageBlobClient.create(length); @@ -1443,7 +1443,7 @@ describe("PageBlobAPIs", () => { }); }); - it("clearPages to internally insert into a non-sequential range @loki", async () => { + it("clearPages to internally insert into a non-sequential range @loki @sql", async () => { const length = 512 * 5; await pageBlobClient.create(length); @@ -1495,7 +1495,7 @@ describe("PageBlobAPIs", () => { }); }); - it("clearPages will fail when start range longer than blob length @loki", async () => { + it("clearPages will fail when start range longer than blob length @loki @sql", async () => { const length = 512 * 2; await pageBlobClient.create(length); @@ -1515,7 +1515,7 @@ describe("PageBlobAPIs", () => { assert.fail(); }); - it("GetPageRanges will fail when start range longer than blob length @loki", async () => { + it("GetPageRanges will fail when start range longer than blob length @loki @sql", async () => { const length = 512 * 2; await pageBlobClient.create(length); @@ -1535,7 +1535,7 @@ describe("PageBlobAPIs", () => { assert.fail(); }); - it("UploadPages will fail when start range longer than blob length @loki", async () => { + it("UploadPages will fail when start range longer than blob length @loki @sql", async () => { const length = 512 * 2; await pageBlobClient.create(length); @@ -1554,7 +1554,7 @@ describe("PageBlobAPIs", () => { assert.fail(); }); - it("clearPages to totally override a non-sequential range @loki", async () => { + it("clearPages to totally override a non-sequential range @loki @sql", async () => { const length = 512 * 5; await pageBlobClient.create(length); @@ -1594,7 +1594,7 @@ describe("PageBlobAPIs", () => { assert.deepStrictEqual((ranges.clearRange || []).length, 0); }); - it("clearPages to left override a non-sequential range @loki", async () => { + it("clearPages to left override a non-sequential range @loki @sql", async () => { const length = 512 * 5; await pageBlobClient.create(length); @@ -1641,7 +1641,7 @@ describe("PageBlobAPIs", () => { }); }); - it("clearPages to right override a non-sequential range @loki", async () => { + it("clearPages to right override a non-sequential range @loki @sql", async () => { const length = 512 * 5; await pageBlobClient.create(length); @@ -1684,7 +1684,7 @@ describe("PageBlobAPIs", () => { }); }); - it("getPageRanges @loki", async () => { + it("getPageRanges @loki @sql", async () => { await pageBlobClient.create(1024); const result = await blobClient.download(0); @@ -1704,7 +1704,7 @@ describe("PageBlobAPIs", () => { assert.equal(page2.pageRange![0].count, 511); }); - it("updateSequenceNumber @loki", async () => { + it("updateSequenceNumber @loki @sql", async () => { await pageBlobClient.create(1024); let propertiesResponse = await pageBlobClient.getProperties(); @@ -1726,7 +1726,7 @@ describe("PageBlobAPIs", () => { }); // devstoreaccount1 is standard storage account which doesn't support premium page blob tiers - it.skip("setAccessTier for Page blob @loki", async () => { + it.skip("setAccessTier for Page blob @loki @sql", async () => { const length = 512 * 5; await pageBlobClient.create(length); let propertiesResponse = await pageBlobClient.getProperties(); diff --git a/tests/blob/apis/service.test.ts b/tests/blob/apis/service.test.ts index 999062aef..60a661e80 100644 --- a/tests/blob/apis/service.test.ts +++ b/tests/blob/apis/service.test.ts @@ -457,7 +457,7 @@ describe("ServiceAPIs", () => { ); }); - it("Get Blob service stats negative @loki", async () => { + it("Get Blob service stats negative @loki @sql", async () => { await serviceClient.getStatistics() .catch((err) => { assert.strictEqual(err.statusCode, 400); @@ -496,7 +496,7 @@ describe("ServiceAPIs - secondary location endpoint", () => { await server.clean(); }); - it("Get Blob service stats @loki", async () => { + it("Get Blob service stats @loki @sql", async () => { await serviceClient.getStatistics() .then((result) => { diff --git a/tests/blob/blockblob.highlevel.test.ts b/tests/blob/blockblob.highlevel.test.ts index 22bac9fb3..3316e5e3c 100644 --- a/tests/blob/blockblob.highlevel.test.ts +++ b/tests/blob/blockblob.highlevel.test.ts @@ -179,7 +179,7 @@ describe("BlockBlobHighlevel", () => { aborter.abort(); } }); - } catch (err) {} + } catch (err) { /**/ } assert.ok(eventTriggered); }).timeout(timeoutForLargeFileUploadingTest); @@ -198,7 +198,7 @@ describe("BlockBlobHighlevel", () => { aborter.abort(); } }); - } catch (err) {} + } catch (err) { /**/ } assert.ok(eventTriggered); }); @@ -314,7 +314,7 @@ describe("BlockBlobHighlevel", () => { aborter.abort(); } }); - } catch (err) {} + } catch (err) { /**/ } assert.ok(eventTriggered); }).timeout(timeoutForLargeFileUploadingTest); diff --git a/tests/blob/handlers/AppendBlobHandler.test.ts b/tests/blob/handlers/AppendBlobHandler.test.ts index 2c4878860..9e0636de1 100644 --- a/tests/blob/handlers/AppendBlobHandler.test.ts +++ b/tests/blob/handlers/AppendBlobHandler.test.ts @@ -96,7 +96,7 @@ describe("AppendBlobHandler", () => { ).thenResolve(extent); describe("create", () => { - it("accepts requests withContent-Length == 0 @loki", async () => { + it("accepts requests withContent-Length == 0 @loki @sql", async () => { const handler = new AppendBlobHandler( instance(metadataStore), instance(extentStore), @@ -108,7 +108,7 @@ describe("AppendBlobHandler", () => { }); }); - it("accepts requests with Content-Length != 0 in loose mode @loki", async () => { + it("accepts requests with Content-Length != 0 in loose mode @loki @sql", async () => { const handler = new AppendBlobHandler( instance(metadataStore), instance(extentStore), @@ -120,7 +120,7 @@ describe("AppendBlobHandler", () => { }); }); - it("rejects requests with Content-Length != 0 @loki", async () => { + it("rejects requests with Content-Length != 0 @loki @sql", async () => { const handler = new AppendBlobHandler( instance(metadataStore), instance(extentStore), @@ -146,7 +146,7 @@ describe("AppendBlobHandler", () => { bufferStream.end(buffer); }); - it("accepts requests with Content-Length != 0 @loki", async () => { + it("accepts requests with Content-Length != 0 @loki @sql", async () => { const handler = new AppendBlobHandler( instance(metadataStore), instance(extentStore), @@ -158,7 +158,7 @@ describe("AppendBlobHandler", () => { }); }); - it("rejects requests with Content-Length == 0 @loki", async () => { + it("rejects requests with Content-Length == 0 @loki @sql", async () => { const handler = new AppendBlobHandler( instance(metadataStore), instance(extentStore), @@ -176,7 +176,7 @@ describe("AppendBlobHandler", () => { ); }); - it("accepts requests with valid MD5 checksum @loki", async () => { + it("accepts requests with valid MD5 checksum @loki @sql", async () => { when(request.getHeader(HeaderConstants.CONTENT_MD5)).thenReturn( "T0EkOEfaaTpPNWwEhhFLxg==" ); @@ -195,7 +195,7 @@ describe("AppendBlobHandler", () => { }); }); - it("rejects requests with invalid MD5 checksum @loki", async () => { + it("rejects requests with invalid MD5 checksum @loki @sql", async () => { when(request.getHeader(HeaderConstants.CONTENT_MD5)).thenReturn( "d3JvbmdfTUQ1X2NoZWNrc3VtCg==" ); diff --git a/tests/blob/pagewithdelimiter.test.ts b/tests/blob/pagewithdelimiter.test.ts index 4416adc5b..6daba2f01 100644 --- a/tests/blob/pagewithdelimiter.test.ts +++ b/tests/blob/pagewithdelimiter.test.ts @@ -36,31 +36,31 @@ describe("PageWithDelimiter", () => { "e/2" ]; - it("handles no blob results @loki", async () => { + it("handles no blob results @Loki @sql", async () => { const page = new PageWithDelimiter(5); const [items, prefixes, marker] = await page.fill(createReader([], 5), namer); checkResult(items, prefixes, marker, 0, 0, ""); }); - it("fills 1 result properly @loki", async () => { + it("fills 1 result properly @Loki @sql", async () => { const page = new PageWithDelimiter(1); const [items, prefixes, marker] = await page.fill(createReader(blobs, 1), namer); checkResult(items, prefixes, marker, 1, 0, "a"); }); - it("fills n results properly @loki", async () => { + it("fills n results properly @Loki @sql", async () => { const page = new PageWithDelimiter(5); const [items, prefixes, marker] = await page.fill(createReader(blobs, 5), namer); checkResult(items, prefixes, marker, 5, 0, "c/sub/1"); }); - it("fills exact count with no continuation @loki", async () => { + it("fills exact count with no continuation @Loki @sql", async () => { const page = new PageWithDelimiter(blobs.length); const [items, prefixes, marker] = await page.fill(createReader(blobs, blobs.length), namer); checkResult(items, prefixes, marker, blobs.length, 0, ""); }); - it("fills smaller than max page with no continuation @loki", async () => { + it("fills smaller than max page with no continuation @Loki @sql", async () => { const page = new PageWithDelimiter(blobs.length+1); const [items, prefixes, marker] = await page.fill(createReader(blobs, blobs.length+1), namer); checkResult(items, prefixes, marker, blobs.length, 0, ""); @@ -71,21 +71,21 @@ describe("PageWithDelimiter", () => { describe("and 1 item page size", () => { - it("handles no blob results @loki", async () => { + it("handles no blob results @Loki @sql", async () => { const blobs: string[] = []; const page = new PageWithDelimiter(1, "/"); const [items, prefixes, marker] = await page.fill(createReader(blobs, 1), namer); checkResult(items, prefixes, marker, 0, 0, ""); }); - it("handles 1 blob results @loki", async () => { + it("handles 1 blob results @Loki @sql", async () => { const blobs = ["a"]; const page = new PageWithDelimiter(1, "/"); const [items, prefixes, marker] = await page.fill(createReader(blobs, 1), namer); checkResult(items, prefixes, marker, 1, 0, ""); }); - it("returns 1 of 2 items with proper continuation @loki", async () => { + it("returns 1 of 2 items with proper continuation @Loki @sql", async () => { const blobs = ["a", "b"]; const page = new PageWithDelimiter(1, "/"); let [items, prefixes, marker] = await page.fill(createReader(blobs, 1), namer); @@ -97,14 +97,14 @@ describe("PageWithDelimiter", () => { checkResult(items, prefixes, marker, 1, 0, ""); }); - it("returns first item when prefixes exist @loki", async () => { + it("returns first item when prefixes exist @Loki @sql", async () => { const blobs = ["a/1", "a/2", "a/3", "a/sub/1"]; const page = new PageWithDelimiter(1, "/", "a/"); const [items, prefixes, marker] = await page.fill(createReader(blobs, 1), namer); checkResult(items, prefixes, marker, 1, 0, "a/1"); }); - it("returns first prefix when blobs exist @loki", async () => { + it("returns first prefix when blobs exist @Loki @sql", async () => { const blobs = ["a/s0/1", "a/s0/2", "a/s0/3", "a/s1/1", "a/s2/2", "a/z"]; const page = new PageWithDelimiter(1, "/", "a/"); const [items, prefixes, marker] = await page.fill(createReader(blobs, 1), namer); @@ -114,21 +114,21 @@ describe("PageWithDelimiter", () => { describe("multiple item page size", () => { - it("squashes prefixes @loki", async () => { + it("squashes prefixes @Loki @sql", async () => { const blobs = ["a/s0/1", "a/s0/2", "a/s0/3", "a/s1/1", "a/s1/2", "a/s2/2", "a/z"]; const page = new PageWithDelimiter(2, "/", "a/"); const [items, prefixes, marker] = await page.fill(createReader(blobs, 2), namer); checkResult(items, prefixes, marker, 0, 2, "a/s1/2"); }); - it("squashes a mix @loki", async () => { + it("squashes a mix @Loki @sql", async () => { const blobs = ["a/a", "a/s0/1", "a/s0/2", "a/s1/1", "a/s1/2", "a/z"]; const page = new PageWithDelimiter(2, "/", "a/"); const [items, prefixes, marker] = await page.fill(createReader(blobs, 2), namer); checkResult(items, prefixes, marker, 1, 1, "a/s0/2"); }); - it("follows squashed pages @loki", async () => { + it("follows squashed pages @Loki @sql", async () => { const blobs = ["a/a", "a/s0/1", "a/s0/2", "a/s1/1", "a/s1/2", "a/z"]; const page = new PageWithDelimiter(2, "/", "a/"); let [items, prefixes, marker] = await page.fill(createReader(blobs, 2), namer); @@ -140,7 +140,7 @@ describe("PageWithDelimiter", () => { checkResult(items, prefixes, marker, 1, 1, ""); }); - it("squashes within one larger page @loki", async () => { + it("squashes within one larger page @Loki @sql", async () => { const blobs = ["a/a", "a/s0/1", "a/s0/2", "a/s1/1", "a/s1/2", "a/z"]; const page = new PageWithDelimiter(4, "/", "a/"); let [items, prefixes, marker] = await page.fill(createReader(blobs, 4), namer); diff --git a/tests/blob/sas.test.ts b/tests/blob/sas.test.ts index ef368492f..e2b4f169c 100644 --- a/tests/blob/sas.test.ts +++ b/tests/blob/sas.test.ts @@ -83,7 +83,8 @@ describe("Shared Access Signature (SAS) authentication", () => { await server.clean(); }); - it("generateAccountSASQueryParameters should generate correct hashes", async () => { + //Doesn't work and shouldn't hardcode results and this test @azure/storage-blob not Azurite + it.skip("generateAccountSASQueryParameters should generate correct hashes", async () => { const startDate = new Date(2022, 3, 16, 14, 31, 48, 0); const endDate = new Date(2022, 3, 17, 14, 31, 48, 0); @@ -338,7 +339,7 @@ describe("Shared Access Signature (SAS) authentication", () => { assert.ok(error); }); - it("Synchronized copy blob should work with write permission in account SAS to override an existing blob @loki", async () => { + it("Synchronized copy blob should work with write permission in account SAS to override an existing blob @loki @sql", async () => { const tmr = new Date(); tmr.setDate(tmr.getDate() + 1); @@ -386,7 +387,7 @@ describe("Shared Access Signature (SAS) authentication", () => { await blob2.syncCopyFromURL(blob1.url); }); - it("Synchronized copy blob shouldn't work without write permission in account SAS to override an existing blob @loki", async () => { + it("Synchronized copy blob shouldn't work without write permission in account SAS to override an existing blob @loki @sql", async () => { const tmr = new Date(); tmr.setDate(tmr.getDate() + 1); @@ -441,7 +442,7 @@ describe("Shared Access Signature (SAS) authentication", () => { assert.ok(error !== undefined); }); - it("Synchronized copy blob should work without write permission in account SAS to an nonexisting blob @loki", async () => { + it("Synchronized copy blob should work without write permission in account SAS to an nonexisting blob @loki @sql", async () => { const tmr = new Date(); tmr.setDate(tmr.getDate() + 1); @@ -488,7 +489,7 @@ describe("Shared Access Signature (SAS) authentication", () => { await blob2.syncCopyFromURL(blob1.url); }); - it("Copy blob should work with write permission in account SAS to override an existing blob @loki", async () => { + it("Copy blob should work with write permission in account SAS to override an existing blob @loki @sql", async () => { const tmr = new Date(); tmr.setDate(tmr.getDate() + 1); @@ -536,7 +537,7 @@ describe("Shared Access Signature (SAS) authentication", () => { await blob2.beginCopyFromURL(blob1.url); }); - it("Copy blob shouldn't work without write permission in account SAS to override an existing blob @loki", async () => { + it("Copy blob shouldn't work without write permission in account SAS to override an existing blob @loki @sql", async () => { const tmr = new Date(); tmr.setDate(tmr.getDate() + 1); @@ -591,7 +592,7 @@ describe("Shared Access Signature (SAS) authentication", () => { assert.ok(error !== undefined); }); - it("Copy blob should work without write permission in account SAS to an nonexisting blob @loki", async () => { + it("Copy blob should work without write permission in account SAS to an nonexisting blob @loki @sql", async () => { const tmr = new Date(); tmr.setDate(tmr.getDate() + 1); @@ -1135,7 +1136,7 @@ describe("Shared Access Signature (SAS) authentication", () => { await containerClient.delete(); }); - it("Synchronized copy blob should work with write permission in blob SAS to override an existing blob @loki", async () => { + it("Synchronized copy blob should work with write permission in blob SAS to override an existing blob @loki @sql", async () => { const now = new Date(); now.setMinutes(now.getMinutes() - 5); // Skip clock skew with server @@ -1182,7 +1183,7 @@ describe("Shared Access Signature (SAS) authentication", () => { await blob2SAS.syncCopyFromURL(blob1.url); }); - it("Synchronized copy blob shouldn't work without write permission in blob SAS to override an existing blob @loki", async () => { + it("Synchronized copy blob shouldn't work without write permission in blob SAS to override an existing blob @loki @sql", async () => { const now = new Date(); now.setMinutes(now.getMinutes() - 5); // Skip clock skew with server @@ -1236,7 +1237,7 @@ describe("Shared Access Signature (SAS) authentication", () => { assert.ok(error !== undefined); }); - it("Synchronized copy blob should work without write permission in account SAS to an nonexisting blob @loki", async () => { + it("Synchronized copy blob should work without write permission in account SAS to an nonexisting blob @loki @sql", async () => { const now = new Date(); now.setMinutes(now.getMinutes() - 5); // Skip clock skew with server @@ -1783,7 +1784,7 @@ describe("Shared Access Signature (SAS) authentication", () => { assert.equal(error.details.code, "BlobArchived"); }); - it("Sync Copy blob across accounts should work and honor metadata when provided @loki", async () => { + it("Sync Copy blob across accounts should work and honor metadata when provided @loki @sql", async () => { const now = new Date(); now.setMinutes(now.getMinutes() - 5); // Skip clock skew with server diff --git a/tests/blob/specialnaming.test.ts b/tests/blob/specialnaming.test.ts index 24a6be889..4535d6954 100644 --- a/tests/blob/specialnaming.test.ts +++ b/tests/blob/specialnaming.test.ts @@ -72,6 +72,7 @@ describe("SpecialNaming", () => { .next() ).value; assert.notDeepEqual(response.segment.blobItems.length, 0); + assert.deepStrictEqual(response.segment.blobItems[0].name, blobName); }); it("Should work with special container and blob names with unicode @loki @sql", async () => { @@ -108,6 +109,7 @@ describe("SpecialNaming", () => { .next() ).value; assert.notDeepEqual(response.segment.blobItems.length, 0); + assert.deepStrictEqual(response.segment.blobItems[0].name, blobName); }); it("Should work with special container and blob names with / @loki @sql", async () => { @@ -125,6 +127,7 @@ describe("SpecialNaming", () => { .next() ).value; assert.notDeepEqual(response.segment.blobItems.length, 0); + assert.deepStrictEqual(response.segment.blobItems[0].name, blobName); }); it("Should work with special container and blob names with / in URL string @loki @sql", async () => { @@ -145,6 +148,7 @@ describe("SpecialNaming", () => { .next() ).value; assert.notDeepEqual(response.segment.blobItems.length, 0); + assert.deepStrictEqual(response.segment.blobItems[0].name, blobName); }); it("Should work with special container and blob names uppercase @loki @sql", async () => { @@ -162,6 +166,7 @@ describe("SpecialNaming", () => { .next() ).value; assert.notDeepEqual(response.segment.blobItems.length, 0); + assert.deepStrictEqual(response.segment.blobItems[0].name, blobName); }); it("Should work with special container and blob names uppercase in URL string @loki @sql", async () => { @@ -182,6 +187,7 @@ describe("SpecialNaming", () => { .next() ).value; assert.notDeepEqual(response.segment.blobItems.length, 0); + assert.deepStrictEqual(response.segment.blobItems[0].name, blobName); }); it("Should work with special blob names Chinese characters @loki @sql", async () => { @@ -201,6 +207,7 @@ describe("SpecialNaming", () => { .next() ).value; assert.notDeepEqual(response.segment.blobItems.length, 0); + assert.deepStrictEqual(response.segment.blobItems[0].name, blobName); }); it("Should work with special blob names Chinese characters in URL string @loki @sql", async () => { @@ -223,6 +230,7 @@ describe("SpecialNaming", () => { .next() ).value; assert.notDeepEqual(response.segment.blobItems.length, 0); + assert.deepStrictEqual(response.segment.blobItems[0].name, blobName); }); it("Should work with special blob name characters @loki @sql", async () => { @@ -246,6 +254,7 @@ describe("SpecialNaming", () => { .next() ).value; assert.notDeepEqual(response.segment.blobItems.length, 0); + assert.deepStrictEqual(response.segment.blobItems[0].name, blobName.replace(/\\/g, "/")); }); it("Should work with special blob name characters in URL string @loki @sql", async () => { @@ -278,6 +287,7 @@ describe("SpecialNaming", () => { .next() ).value; assert.notDeepEqual(response.segment.blobItems.length, 0); + assert.deepStrictEqual(response.segment.blobItems[0].name, blobName.replace(/\\/g, "/")); }); it("Should work with special blob name Russian URI encoded @loki @sql", async () => { @@ -296,6 +306,7 @@ describe("SpecialNaming", () => { .next() ).value; assert.notDeepEqual(response.segment.blobItems.length, 0); + assert.deepStrictEqual(response.segment.blobItems[0].name, blobNameEncoded); }); it("Should work with special blob name Russian @loki @sql", async () => { @@ -313,6 +324,7 @@ describe("SpecialNaming", () => { .next() ).value; assert.notDeepEqual(response.segment.blobItems.length, 0); + assert.deepStrictEqual(response.segment.blobItems[0].name, blobName); }); it("Should work with special blob name Russian in URL string @loki @sql", async () => { @@ -333,6 +345,7 @@ describe("SpecialNaming", () => { .next() ).value; assert.notDeepEqual(response.segment.blobItems.length, 0); + assert.deepStrictEqual(response.segment.blobItems[0].name, blobName); }); it("Should work with special blob name Arabic URI encoded @loki @sql", async () => { @@ -351,6 +364,7 @@ describe("SpecialNaming", () => { .next() ).value; assert.notDeepEqual(response.segment.blobItems.length, 0); + assert.deepStrictEqual(response.segment.blobItems[0].name, blobNameEncoded); }); it("Should work with special blob name Arabic @loki @sql", async () => { @@ -368,6 +382,7 @@ describe("SpecialNaming", () => { .next() ).value; assert.notDeepEqual(response.segment.blobItems.length, 0); + assert.deepStrictEqual(response.segment.blobItems[0].name, blobName); }); it("Should work with special blob name Arabic in URL string @loki @sql", async () => { @@ -388,6 +403,7 @@ describe("SpecialNaming", () => { .next() ).value; assert.notDeepEqual(response.segment.blobItems.length, 0); + assert.deepStrictEqual(response.segment.blobItems[0].name, blobName); }); it("Should work with special blob name Japanese URI encoded @loki @sql", async () => { @@ -406,6 +422,7 @@ describe("SpecialNaming", () => { .next() ).value; assert.notDeepEqual(response.segment.blobItems.length, 0); + assert.deepStrictEqual(response.segment.blobItems[0].name, blobNameEncoded); }); it("Should work with special blob name Japanese @loki @sql", async () => { @@ -423,6 +440,7 @@ describe("SpecialNaming", () => { .next() ).value; assert.notDeepEqual(response.segment.blobItems.length, 0); + assert.deepStrictEqual(response.segment.blobItems[0].name, blobName); }); it("Should work with special blob name Japanese in URL string @loki @sql", async () => { @@ -443,6 +461,7 @@ describe("SpecialNaming", () => { .next() ).value; assert.notDeepEqual(response.segment.blobItems.length, 0); + assert.deepStrictEqual(response.segment.blobItems[0].name, blobName); }); it(`Should work with production style URL when ${productionStyleHostName} is resolvable`, async () => { @@ -482,6 +501,7 @@ describe("SpecialNaming", () => { .next() ).value; assert.notDeepEqual(response.segment.blobItems.length, 0); + assert.deepStrictEqual(response.segment.blobItems[0].name, blobName); }, () => { // Cannot perform this test. We need devstoreaccount1.localhost to resolve to 127.0.0.1. @@ -527,6 +547,7 @@ describe("SpecialNaming", () => { .next() ).value; assert.notDeepEqual(response.segment.blobItems.length, 0); + assert.deepStrictEqual(response.segment.blobItems[0].name, blobName); }, () => { // Cannot perform this test. We need host.docker.internal to resolve to 127.0.0.1. diff --git a/tests/blob/utils.test.ts b/tests/blob/utils.test.ts index c0d897148..a60c5d38e 100644 --- a/tests/blob/utils.test.ts +++ b/tests/blob/utils.test.ts @@ -2,7 +2,7 @@ import assert = require("assert"); import { convertRawHeadersToMetadata } from "../../src/common/utils/utils"; describe("Utils", () => { - it("convertRawHeadersToMetadata should work", () => { + it("convertRawHeadersToMetadata should work @loki @sql", () => { // upper case, lower case keys/values const metadata = convertRawHeadersToMetadata([ "x-ms-meta-Name1", @@ -22,7 +22,7 @@ describe("Utils", () => { }); }); - it("convertRawHeadersToMetadata should work with duplicated metadata", () => { + it("convertRawHeadersToMetadata should work with duplicated metadata @loki @sql", () => { const metadata = convertRawHeadersToMetadata([ "x-ms-meta-name1", "Value", @@ -34,7 +34,7 @@ describe("Utils", () => { }); }); - it("convertRawHeadersToMetadata should work with empty metadata", () => { + it("convertRawHeadersToMetadata should work with empty metadata @loki @sql", () => { const metadata = convertRawHeadersToMetadata([ "x-ms-meta-Name1", "", @@ -47,12 +47,12 @@ describe("Utils", () => { }); }); - it("convertRawHeadersToMetadata should work with empty raw headers", () => { + it("convertRawHeadersToMetadata should work with empty raw headers @loki @sql", () => { const metadata = convertRawHeadersToMetadata(); assert.deepStrictEqual(metadata, undefined); }); - it("convertRawHeadersToMetadata should work with empty raw headers array", () => { + it("convertRawHeadersToMetadata should work with empty raw headers array @loki @sql", () => { const metadata = convertRawHeadersToMetadata([]); assert.deepStrictEqual(metadata, undefined); }); From 4613bc27a4a4f388ecad45b775478b1cff6c9b85 Mon Sep 17 00:00:00 2001 From: Mahmoud Bahaa Date: Sat, 22 Apr 2023 04:10:18 +0200 Subject: [PATCH 2/4] * Full support for sql for the same features supported by Loki * Added better support for using postgreSQL without breaking mysql --- src/blob/persistence/SqlBlobMetadataStore.ts | 1074 ++++++++++++------ 1 file changed, 751 insertions(+), 323 deletions(-) diff --git a/src/blob/persistence/SqlBlobMetadataStore.ts b/src/blob/persistence/SqlBlobMetadataStore.ts index 0013185e2..a1cbe2c30 100644 --- a/src/blob/persistence/SqlBlobMetadataStore.ts +++ b/src/blob/persistence/SqlBlobMetadataStore.ts @@ -20,7 +20,7 @@ import { import { convertDateTimeStringMsTo7Digital } from "../../common/utils/utils"; import { newEtag } from "../../common/utils/utils"; import { validateReadConditions } from "../conditions/ReadConditionalHeadersValidator"; -import { validateWriteConditions } from "../conditions/WriteConditionalHeadersValidator"; +import { validateSequenceNumberWriteConditions, validateWriteConditions } from "../conditions/WriteConditionalHeadersValidator"; import StorageErrorFactory from "../errors/StorageErrorFactory"; import * as Models from "../generated/artifacts/models"; import Context from "../generated/Context"; @@ -37,7 +37,8 @@ import { ILease } from "../lease/ILeaseState"; import LeaseFactory from "../lease/LeaseFactory"; import { DEFAULT_LIST_BLOBS_MAX_RESULTS, - DEFAULT_LIST_CONTAINERS_MAX_RESULTS + DEFAULT_LIST_CONTAINERS_MAX_RESULTS, + MAX_APPEND_BLOB_BLOCK_COUNT } from "../utils/constants"; import BlobReferredExtentsAsyncIterator from "./BlobReferredExtentsAsyncIterator"; import IBlobMetadataStore, { @@ -67,24 +68,15 @@ import IBlobMetadataStore, { SetContainerAccessPolicyOptions } from "./IBlobMetadataStore"; import PageWithDelimiter from "./PageWithDelimiter"; +import PageBlobRangesManager from "../handlers/PageBlobRangesManager"; // tslint:disable: max-classes-per-file -class ServicesModel extends Model {} -class ContainersModel extends Model {} -class BlobsModel extends Model {} -class BlocksModel extends Model {} +export class ServicesModel extends Model {} +export class ContainersModel extends Model {} +export class BlobsModel extends Model {} +export class BlocksModel extends Model {} // class PagesModel extends Model {} -interface IBlobContentProperties { - contentLength?: number; - contentType?: string; - contentEncoding?: string; - contentLanguage?: string; - contentMD5?: Uint8Array; - contentDisposition?: string; - cacheControl?: string; -} - /** * A SQL based Blob metadata storage implementation based on Sequelize. * Refer to CONTRIBUTION.md for how to setup SQL database environment. @@ -96,7 +88,10 @@ interface IBlobContentProperties { export default class SqlBlobMetadataStore implements IBlobMetadataStore { private initialized: boolean = false; private closed: boolean = false; - private readonly sequelize: Sequelize; + protected readonly sequelize: Sequelize; + private readonly isPostgres: boolean; + + private readonly pageBlobRangesManager = new PageBlobRangesManager(); /** * Creates an instance of SqlBlobMetadataStore. @@ -107,7 +102,9 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { */ public constructor( connectionURI: string, - sequelizeOptions?: SequelizeOptions + sequelizeOptions?: SequelizeOptions, + private readonly clearDB: boolean = false, + protected readonly softDelete: boolean = true ) { // Enable encrypt connection for SQL Server if (connectionURI.startsWith("mssql") && sequelizeOptions) { @@ -116,6 +113,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { (sequelizeOptions.dialectOptions as any).options || {}; (sequelizeOptions.dialectOptions as any).options.encrypt = true; } + this.isPostgres = connectionURI.startsWith("postgres"); this.sequelize = new Sequelize(connectionURI, sequelizeOptions); } @@ -187,6 +185,10 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { metadata: { type: "VARCHAR(4095)" }, + properties: { + allowNull: true, + type: "VARCHAR(4095)" + }, containerAcl: { type: "VARCHAR(1023)" }, @@ -224,7 +226,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { allowNull: false }, blobName: { - type: "VARCHAR(255)", + type: this.isPostgres ? "VARCHAR(65535)" : "VARCHAR(255)", allowNull: false }, snapshot: { @@ -237,37 +239,8 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { primaryKey: true, autoIncrement: true }, - lastModified: { - allowNull: false, - type: DATE(6) - }, - creationTime: { - allowNull: false, - type: DATE(6) - }, - accessTierChangeTime: { - allowNull: true, - type: DATE(6) - }, - accessTierInferred: { - type: BOOLEAN - }, - etag: { - allowNull: false, - type: "VARCHAR(127)" - }, - blobType: { - allowNull: false, - type: "VARCHAR(31)" - }, - blobSequenceNumber: { - type: "VARCHAR(63)" - }, - accessTier: { - type: "VARCHAR(31)" - }, - contentProperties: { - type: "VARCHAR(1023)" + properties: { + type: "VARCHAR(4095)" }, lease: { type: "VARCHAR(1023)" @@ -284,8 +257,26 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { persistency: { type: "VARCHAR(255)" }, + isDirectory: { + type: BOOLEAN + }, + permissions: { + type: "VARCHAR(255)" + }, + acl: { + type: "VARCHAR(255)" + }, + owner: { + type: "VARCHAR(255)" + }, + group: { + type: "VARCHAR(255)" + }, committedBlocksInOrder: { - type: TEXT({ length: "medium" }) + type: this.isPostgres ? "VARCHAR(65535)" : TEXT("medium") + }, + pageRangesInOrder: { + type: this.isPostgres ? "VARCHAR(65535)" : TEXT("medium") }, metadata: { type: "VARCHAR(2047)" @@ -326,12 +317,12 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { allowNull: false }, blobName: { - type: "VARCHAR(255)", + type: this.isPostgres ? "VARCHAR(65535)" : "VARCHAR(255)", allowNull: false }, // TODO: Check max block name length blockName: { - type: "VARCHAR(64)", + type: this.isPostgres ? "VARCHAR(65535)" : "VARCHAR(64)", allowNull: false }, deleting: { @@ -361,8 +352,12 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { } ); - // TODO: sync() is only for development purpose, use migration for production - await this.sequelize.sync(); + if (this.clearDB) { + await this.sequelize.sync({ force: true }); + } else { + // TODO: sync() is only for development purpose, use migration for production + await this.sequelize.sync(); + } this.initialized = true; } @@ -638,33 +633,8 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { transaction: t }); - // TODO: GC blobs under deleting status - await BlobsModel.update( - { - deleting: literal("deleting + 1") - }, - { - where: { - accountName: account, - containerName: container - }, - transaction: t - } - ); - - // TODO: GC blocks under deleting status - await BlocksModel.update( - { - deleting: literal("deleting + 1") - }, - { - where: { - accountName: account, - containerName: container - }, - transaction: t - } - ); + await this.destroyBlob(account, container, undefined, undefined, t); + await this.destroyBlock(account, container, undefined, undefined, t); /* Transaction ends */ }); } @@ -1435,7 +1405,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { }); } - public getBlockList( + public async getBlockList( context: Context, account: string, container: string, @@ -1663,18 +1633,12 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { transaction: t }); - await BlocksModel.update( - { - deleting: literal("deleting + 1") - }, - { - where: { - accountName: blob.accountName, - containerName: blob.containerName, - blobName: blob.name - }, - transaction: t - } + await this.destroyBlock( + blob.accountName, + blob.containerName, + blob.name, + undefined, + t ); }); } @@ -1723,19 +1687,22 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { throw StorageErrorFactory.getBlobNotFound(context.contextId); } - // TODO: Return blobCommittedBlockCount for append blob - - return LeaseFactory.createLeaseState( + const res = LeaseFactory.createLeaseState( new BlobLeaseAdapter(blobModel), context ) .validate(new BlobReadLeaseValidator(leaseAccessConditions)) .sync(new BlobLeaseSyncer(blobModel)); - }); - } - public undeleteBlob(): Promise { - throw new Error("Method not implemented."); + return { + properties: res.properties, + metadata: res.metadata, + blobCommittedBlockCount: + res.properties.blobType === Models.BlobType.AppendBlob + ? (res.committedBlocksInOrder || []).length + : undefined + }; + }); } public async createSnapshot( @@ -1879,52 +1846,14 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { if (count > 1) { throw StorageErrorFactory.getSnapshotsPresent(context.contextId!); } else { - await BlobsModel.update( - { - deleting: literal("deleting + 1") - }, - { - where: { - accountName: account, - containerName: container, - blobName: blob - }, - transaction: t - } - ); - - await BlocksModel.update( - { - deleting: literal("deleting + 1") - }, - { - where: { - accountName: account, - containerName: container, - blobName: blob - }, - transaction: t - } - ); + await this.destroyBlob(account, container, blob, undefined, t); + await this.destroyBlock(account, container, blob, undefined, t); } } // Scenario: Delete one snapshot only if (!againstBaseBlob) { - await BlobsModel.update( - { - deleting: literal("deleting + 1") - }, - { - where: { - accountName: account, - containerName: container, - blobName: blob, - snapshot: blobModel.snapshot - }, - transaction: t - } - ); + await this.destroyBlob(account, container, blob, blobModel.snapshot, t); } // Scenario: Delete base blob and snapshots @@ -1932,33 +1861,8 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { againstBaseBlob && options.deleteSnapshots === Models.DeleteSnapshotsOptionType.Include ) { - await BlobsModel.update( - { - deleting: literal("deleting + 1") - }, - { - where: { - accountName: account, - containerName: container, - blobName: blob - }, - transaction: t - } - ); - - await BlocksModel.update( - { - deleting: literal("deleting + 1") - }, - { - where: { - accountName: account, - containerName: container, - blobName: blob - }, - transaction: t - } - ); + await this.destroyBlob(account, container, blob, undefined, t); + await this.destroyBlock(account, container, blob, undefined, t); } // Scenario: Delete all snapshots only @@ -1966,20 +1870,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { againstBaseBlob && options.deleteSnapshots === Models.DeleteSnapshotsOptionType.Only ) { - await BlobsModel.update( - { - deleting: literal("deleting + 1") - }, - { - where: { - accountName: account, - containerName: container, - blobName: blob, - snapshot: { [Op.gt]: "" } - }, - transaction: t - } - ); + await this.destroyBlob(account, container, blob, { [Op.gt]: "" }, t); } }); } @@ -2060,7 +1951,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { }); } - public setBlobMetadata( + public async setBlobMetadata( context: Context, account: string, container: string, @@ -2105,13 +1996,10 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { const lastModified = context.startTime! || new Date(); const etag = newEtag(); - await BlobsModel.update( - { - metadata: this.serializeModelValue(metadata) || null, - lastModified, - etag, - ...this.convertLeaseToDbModel(new BlobLeaseAdapter(blobModel)) - }, + blobModel.metadata = metadata; + blobModel.properties.lastModified = lastModified; + + await BlobsModel.update(this.convertBlobModelToDbModel(blobModel), { where: { accountName: account, @@ -2179,7 +2067,8 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { context ).acquire(duration, proposedLeaseId).lease; - await BlobsModel.update(this.convertLeaseToDbModel(lease), { + new BlobLeaseSyncer(blobModel).sync(lease); + await BlobsModel.update(this.convertBlobModelToDbModel(blobModel), { where: { accountName: account, containerName: container, @@ -2235,7 +2124,8 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { context ).release(leaseId).lease; - await BlobsModel.update(this.convertLeaseToDbModel(lease), { + new BlobLeaseSyncer(blobModel).sync(lease); + await BlobsModel.update(this.convertBlobModelToDbModel(blobModel), { where: { accountName: account, containerName: container, @@ -2291,7 +2181,8 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { context ).renew(leaseId).lease; - await BlobsModel.update(this.convertLeaseToDbModel(lease), { + new BlobLeaseSyncer(blobModel).sync(lease); + await BlobsModel.update(this.convertBlobModelToDbModel(blobModel), { where: { accountName: account, containerName: container, @@ -2348,7 +2239,8 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { context ).change(leaseId, proposedLeaseId).lease; - await BlobsModel.update(this.convertLeaseToDbModel(lease), { + new BlobLeaseSyncer(blobModel).sync(lease); + await BlobsModel.update(this.convertBlobModelToDbModel(blobModel), { where: { accountName: account, containerName: container, @@ -2413,7 +2305,8 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { ) : 0; - await BlobsModel.update(this.convertLeaseToDbModel(lease), { + new BlobLeaseSyncer(blobModel).sync(lease); + await BlobsModel.update(this.convertBlobModelToDbModel(blobModel), { where: { accountName: account, containerName: container, @@ -2476,7 +2369,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { return undefined; } - const blobType = this.getModelValue(res, "blobType", true); + const blobType = this.getModelValue(res, "properties", true).blobType; const isCommitted = this.getModelValue(res, "isCommitted", true); return { blobType, isCommitted }; @@ -2542,6 +2435,15 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { ); } + // Copy if not exists + if ( + options.modifiedAccessConditions && + options.modifiedAccessConditions.ifNoneMatch === "*" && + destBlob + ) { + throw StorageErrorFactory.getBlobAlreadyExists(context.contextId); + } + // If source is uncommitted or deleted if ( sourceBlob === undefined || @@ -2616,7 +2518,12 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { leaseBreakTime: destBlob !== undefined ? destBlob.leaseBreakTime : undefined, committedBlocksInOrder: sourceBlob.committedBlocksInOrder, - persistency: sourceBlob.persistency + persistency: sourceBlob.persistency, + isDirectory: sourceBlob.isDirectory, + permissions: sourceBlob.permissions, + acl: sourceBlob.acl, + owner: sourceBlob.owner, + group: sourceBlob.group }; if ( @@ -2649,14 +2556,207 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { }); } - public copyFromURL( + /** + * Copy from Url. + * + * @param {Context} context + * @param {BlobId} source + * @param {BlobId} destination + * @param {string} copySource + * @param {(Models.BlobMetadata | undefined)} metadata + * @param {(Models.AccessTier | undefined)} tier + * @param {Models.BlobCopyFromURLOptionalParams} [leaseAccessConditions] + * @returns {Promise} + * @memberof LokiBlobMetadataStore + */ + public async copyFromURL( context: Context, source: BlobId, destination: BlobId, copySource: string, - metadata: Models.BlobMetadata | undefined + metadata: Models.BlobMetadata | undefined, + tier: Models.AccessTier | undefined, + options: Models.BlobCopyFromURLOptionalParams = {} ): Promise { - throw new Error("Method not implemented."); + return this.sequelize.transaction(async (t) => { + const sourceBlob = await this.getBlobWithLeaseUpdated( + source.account, + source.container, + source.blob, + source.snapshot, + context, + true, + true + ); + + options.sourceModifiedAccessConditions = + options.sourceModifiedAccessConditions || {}; + validateReadConditions( + context, + { + ifModifiedSince: + options.sourceModifiedAccessConditions.sourceIfModifiedSince, + ifUnmodifiedSince: + options.sourceModifiedAccessConditions.sourceIfUnmodifiedSince, + ifMatch: options.sourceModifiedAccessConditions.sourceIfMatch, + ifNoneMatch: options.sourceModifiedAccessConditions.sourceIfNoneMatch + }, + sourceBlob + ); + + const destBlob = await this.getBlobWithLeaseUpdated( + destination.account, + destination.container, + destination.blob, + undefined, + context, + false + ); + + validateWriteConditions( + context, + options.modifiedAccessConditions, + destBlob + ); + + // Copy if not exists + if ( + options.modifiedAccessConditions && + options.modifiedAccessConditions.ifNoneMatch === "*" && + destBlob + ) { + throw StorageErrorFactory.getBlobAlreadyExists(context.contextId); + } + + if (destBlob) { + const lease = new BlobLeaseAdapter(destBlob); + new BlobWriteLeaseSyncer(destBlob).sync(lease); + new BlobWriteLeaseValidator(options.leaseAccessConditions).validate( + lease, + context + ); + } + + // If source is uncommitted or deleted + if ( + sourceBlob === undefined || + sourceBlob.deleted || + !sourceBlob.isCommitted + ) { + throw StorageErrorFactory.getBlobNotFound(context.contextId); + } + + if (sourceBlob.properties.accessTier === Models.AccessTier.Archive) { + throw StorageErrorFactory.getBlobArchived(context.contextId); + } + + await this.checkContainerExist( + context, + destination.account, + destination.container + ); + + // Deep clone a copied blob + const copiedBlob: BlobModel = { + name: destination.blob, + deleted: false, + snapshot: "", + properties: { + ...sourceBlob.properties, + creationTime: context.startTime!, + lastModified: context.startTime!, + etag: newEtag(), + leaseStatus: + destBlob !== undefined + ? destBlob.properties.leaseStatus + : Models.LeaseStatusType.Unlocked, + leaseState: + destBlob !== undefined + ? destBlob.properties.leaseState + : Models.LeaseStateType.Available, + leaseDuration: + destBlob !== undefined + ? destBlob.properties.leaseDuration + : undefined, + copyId: uuid(), + copyStatus: Models.CopyStatusType.Success, + copySource, + copyProgress: sourceBlob.properties.contentLength + ? `${sourceBlob.properties.contentLength}/${sourceBlob.properties.contentLength}` + : undefined, + copyCompletionTime: context.startTime, + copyStatusDescription: undefined, + incrementalCopy: false, + destinationSnapshot: undefined, + deletedTime: undefined, + remainingRetentionDays: undefined, + archiveStatus: undefined, + accessTierChangeTime: undefined + }, + metadata: + metadata === undefined || Object.keys(metadata).length === 0 + ? { ...sourceBlob.metadata } + : metadata, + accountName: destination.account, + containerName: destination.container, + pageRangesInOrder: sourceBlob.pageRangesInOrder, + isCommitted: sourceBlob.isCommitted, + leaseDurationSeconds: + destBlob !== undefined ? destBlob.leaseDurationSeconds : undefined, + leaseId: destBlob !== undefined ? destBlob.leaseId : undefined, + leaseExpireTime: + destBlob !== undefined ? destBlob.leaseExpireTime : undefined, + leaseBreakTime: + destBlob !== undefined ? destBlob.leaseBreakTime : undefined, + committedBlocksInOrder: sourceBlob.committedBlocksInOrder, + persistency: sourceBlob.persistency, + isDirectory: sourceBlob.isDirectory, + permissions: sourceBlob.permissions, + acl: sourceBlob.acl, + owner: sourceBlob.owner, + group: sourceBlob.group + }; + + if ( + copiedBlob.properties.blobType === Models.BlobType.BlockBlob && + tier !== undefined + ) { + copiedBlob.properties.accessTier = this.parseTier(tier); + if (copiedBlob.properties.accessTier === undefined) { + throw StorageErrorFactory.getInvalidHeaderValue(context.contextId, { + HeaderName: "x-ms-access-tier", + HeaderValue: `${tier}` + }); + } + } + + if ( + copiedBlob.properties.blobType === Models.BlobType.PageBlob && + tier !== undefined + ) { + throw StorageErrorFactory.getInvalidHeaderValue(context.contextId, { + HeaderName: "x-ms-access-tier", + HeaderValue: `${tier}` + }); + } + + if (destBlob) { + await BlobsModel.destroy({ + where: { + accountName: destBlob.accountName, + containerName: destBlob.containerName, + blobName: destBlob.name + }, + transaction: t + }); + } + + await BlobsModel.upsert(this.convertBlobModelToDbModel(copiedBlob), { + transaction: t + }); + + return copiedBlob.properties; + }); } public setTier( @@ -2734,12 +2834,11 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { context.contextId! ); } - await BlobsModel.update( - { - accessTier, - accessTierInferred: false, - accessTierChangeTime: context.startTime - }, + blobModel.properties.accessTier = accessTier; + blobModel.properties.accessTierInferred = false; + blobModel.properties.accessTierChangeTime = context.startTime; + + await BlobsModel.update(this.convertBlobModelToDbModel(blobModel), { where: { accountName: account, @@ -2756,30 +2855,118 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { }); } - public uploadPages( + public async uploadPages( context: Context, blob: BlobModel, start: number, end: number, persistency: IExtentChunk, leaseAccessConditions?: Models.LeaseAccessConditions, - modifiedAccessConditions?: Models.ModifiedAccessConditions + modifiedAccessConditions?: Models.ModifiedAccessConditions, + sequenceNumberAccessConditions?: Models.SequenceNumberAccessConditions ): Promise { - throw new Error("Method not implemented."); + return await this.sequelize.transaction(async (t) => { + const doc = await this.getBlobWithLeaseUpdated( + blob.accountName, + blob.containerName, + blob.name, + blob.snapshot, + context!, + false, + true, + t + ); + + validateWriteConditions(context, modifiedAccessConditions, doc); + + validateSequenceNumberWriteConditions( + context, + sequenceNumberAccessConditions, + doc + ); + + if (!doc) { + throw StorageErrorFactory.getBlobNotFound(context.contextId); + } + + if (doc.properties.blobType !== Models.BlobType.PageBlob) { + throw StorageErrorFactory.getBlobInvalidBlobType(context.contextId); + } + + const lease = new BlobLeaseAdapter(doc); + new BlobWriteLeaseValidator(leaseAccessConditions).validate(lease, context); + + this.pageBlobRangesManager.mergeRange(doc.pageRangesInOrder || [], { + start, + end, + persistency + }); + + // set lease state to available if it's expired + new BlobWriteLeaseSyncer(doc).sync(lease); + + doc.properties.etag = newEtag(); + doc.properties.lastModified = context.startTime || new Date(); + + await BlobsModel.upsert(this.convertBlobModelToDbModel(doc), { transaction: t }); + return doc.properties; + }); } - public clearRange( + public async clearRange( context: Context, blob: BlobModel, start: number, end: number, leaseAccessConditions?: Models.LeaseAccessConditions, - modifiedAccessConditions?: Models.ModifiedAccessConditions + modifiedAccessConditions?: Models.ModifiedAccessConditions, + sequenceNumberAccessConditions?: Models.SequenceNumberAccessConditions ): Promise { - throw new Error("Method not implemented."); + return await this.sequelize.transaction(async (t) => { + const doc = await this.getBlobWithLeaseUpdated( + blob.accountName, + blob.containerName, + blob.name, + blob.snapshot, + context!, + false, + true, + t + ); + + validateWriteConditions(context, modifiedAccessConditions, doc); + + validateSequenceNumberWriteConditions( + context, + sequenceNumberAccessConditions, + doc + ); + + if (!doc) { + throw StorageErrorFactory.getBlobNotFound(context.contextId); + } + + const lease = new BlobLeaseAdapter(doc); + new BlobWriteLeaseValidator(leaseAccessConditions).validate(lease, context); + + this.pageBlobRangesManager.clearRange(doc.pageRangesInOrder || [], { + start, + end + }); + + // TODO: Check other blob update operations need lease reset or not + // set lease state to available if it's expired + new BlobWriteLeaseSyncer(doc).sync(lease); + + doc.properties.etag = newEtag(); + doc.properties.lastModified = context.startTime || new Date(); + + await BlobsModel.upsert(this.convertBlobModelToDbModel(doc), { transaction: t }); + return doc.properties; + }); } - public getPageRanges( + public async getPageRanges( context: Context, account: string, container: string, @@ -2788,10 +2975,38 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { leaseAccessConditions?: Models.LeaseAccessConditions, modifiedAccessConditions?: Models.ModifiedAccessConditions ): Promise { - throw new Error("Method not implemented."); + const doc = await this.getBlobWithLeaseUpdated( + account, + container, + blob, + snapshot, + context, + false, + true + ); + + validateReadConditions(context, modifiedAccessConditions, doc); + + if (!doc) { + throw StorageErrorFactory.getBlobNotFound(context.contextId); + } + + if (doc.properties.blobType !== Models.BlobType.PageBlob) { + throw StorageErrorFactory.getBlobInvalidBlobType(context.contextId); + } + + new BlobReadLeaseValidator(leaseAccessConditions).validate( + new BlobLeaseAdapter(doc), + context + ); + + return { + properties: doc.properties, + pageRangesInOrder: doc.pageRangesInOrder + }; } - public resizePageBlob( + public async resizePageBlob( context: Context, account: string, container: string, @@ -2800,21 +3015,145 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { leaseAccessConditions?: Models.LeaseAccessConditions, modifiedAccessConditions?: Models.ModifiedAccessConditions ): Promise { - throw new Error("Method not implemented."); + return await this.sequelize.transaction(async (t) => { + const doc = await this.getBlobWithLeaseUpdated( + account, + container, + blob, + undefined, + context, + false, + true, + t + ); + + validateWriteConditions(context, modifiedAccessConditions, doc); + + if (!doc) { + throw StorageErrorFactory.getBlobNotFound(context.contextId); + } + + if (doc.properties.blobType !== Models.BlobType.PageBlob) { + throw StorageErrorFactory.getInvalidOperation( + context.contextId, + "Resize could only be against a page blob." + ); + } + + const lease = new BlobLeaseAdapter(doc); + new BlobWriteLeaseValidator(leaseAccessConditions).validate(lease, context); + + doc.pageRangesInOrder = doc.pageRangesInOrder || []; + if (doc.properties.contentLength! > blobContentLength) { + const start = blobContentLength; + const end = doc.properties.contentLength! - 1; + this.pageBlobRangesManager.clearRange(doc.pageRangesInOrder || [], { + start, + end + }); + } + + doc.properties.contentLength = blobContentLength; + doc.properties.lastModified = context.startTime || new Date(); + doc.properties.etag = newEtag(); + + new BlobWriteLeaseSyncer(doc).sync(lease); + + await BlobsModel.upsert(this.convertBlobModelToDbModel(doc), { transaction: t }); + return doc.properties; + }); } - public updateSequenceNumber( + public async updateSequenceNumber( context: Context, account: string, container: string, blob: string, sequenceNumberAction: Models.SequenceNumberActionType, - blobSequenceNumber: number | undefined + blobSequenceNumber: number | undefined, + leaseAccessConditions?: Models.LeaseAccessConditions, + modifiedAccessConditions?: Models.ModifiedAccessConditions ): Promise { - throw new Error("Method not implemented."); + return await this.sequelize.transaction(async (t) => { + const doc = await this.getBlobWithLeaseUpdated( + account, + container, + blob, + undefined, + context, + false, + true, + t + ); + + validateWriteConditions(context, modifiedAccessConditions, doc); + + if (!doc) { + throw StorageErrorFactory.getBlobNotFound(context.contextId); + } + + if (doc.properties.blobType !== Models.BlobType.PageBlob) { + throw StorageErrorFactory.getInvalidOperation( + context.contextId!, + "Get Page Ranges could only be against a page blob." + ); + } + + const lease = new BlobLeaseAdapter(doc); + new BlobWriteLeaseValidator(leaseAccessConditions).validate(lease, context); + + if (doc.properties.blobSequenceNumber === undefined) { + doc.properties.blobSequenceNumber = 0; + } + + switch (sequenceNumberAction) { + case Models.SequenceNumberActionType.Max: + if (blobSequenceNumber === undefined) { + throw StorageErrorFactory.getInvalidOperation( + context.contextId!, + "x-ms-blob-sequence-number is required when x-ms-sequence-number-action is set to max." + ); + } + doc.properties.blobSequenceNumber = Math.max( + doc.properties.blobSequenceNumber, + blobSequenceNumber + ); + break; + case Models.SequenceNumberActionType.Increment: + if (blobSequenceNumber !== undefined) { + throw StorageErrorFactory.getInvalidOperation( + context.contextId!, + "x-ms-blob-sequence-number cannot be provided when x-ms-sequence-number-action is set to increment." + ); + } + doc.properties.blobSequenceNumber++; + break; + case Models.SequenceNumberActionType.Update: + if (blobSequenceNumber === undefined) { + throw StorageErrorFactory.getInvalidOperation( + context.contextId!, + "x-ms-blob-sequence-number is required when x-ms-sequence-number-action is set to update." + ); + } + doc.properties.blobSequenceNumber = blobSequenceNumber; + break; + default: + throw StorageErrorFactory.getInvalidOperation( + context.contextId!, + "Unsupported x-ms-sequence-number-action value." + ); + } + + doc.properties.etag = newEtag(); + doc.properties.lastModified = context.startTime!; + new BlobWriteLeaseSyncer(doc).sync(lease); + + await BlobsModel.upsert(this.convertBlobModelToDbModel(doc), { transaction: t }); + return doc.properties; + }); } - public appendBlock( + public async appendBlock( context: Context, block: BlockModel, leaseAccessConditions?: Models.LeaseAccessConditions | undefined, @@ -2823,7 +3162,78 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { | Models.AppendPositionAccessConditions | undefined ): Promise { - throw new Error("Method not implemented."); + return await this.sequelize.transaction(async (t) => { + const doc = await this.getBlobWithLeaseUpdated( + block.accountName, + block.containerName, + block.blobName, + undefined, + context, + false, + true + ); + + validateWriteConditions(context, modifiedAccessConditions, doc); + + if (!doc) { + throw StorageErrorFactory.getBlobNotFound(context.contextId); + } + + new BlobWriteLeaseValidator(leaseAccessConditions).validate( + new BlobLeaseAdapter(doc), + context + ); + + if (doc.properties.blobType !== Models.BlobType.AppendBlob) { + throw StorageErrorFactory.getBlobInvalidBlobType(context.contextId); + } + + if ( + (doc.committedBlocksInOrder || []).length >= MAX_APPEND_BLOB_BLOCK_COUNT + ) { + throw StorageErrorFactory.getBlockCountExceedsLimit(context.contextId); + } + + if ( + appendPositionAccessConditions !== undefined && + appendPositionAccessConditions.appendPosition !== undefined + ) { + if ( + (doc.properties.contentLength || 0) !== + appendPositionAccessConditions.appendPosition + ) { + throw StorageErrorFactory.getAppendPositionConditionNotMet( + context.contextId + ); + } + } + + if ( + appendPositionAccessConditions !== undefined && + appendPositionAccessConditions.maxSize !== undefined + ) { + if ( + (doc.properties.contentLength || 0) + block.size > + appendPositionAccessConditions.maxSize + ) { + throw StorageErrorFactory.getMaxBlobSizeConditionNotMet( + context.contextId + ); + } + } + + doc.committedBlocksInOrder = doc.committedBlocksInOrder || []; + doc.committedBlocksInOrder.push(block); + doc.properties.etag = newEtag(); + doc.properties.lastModified = context.startTime || new Date(); + doc.properties.contentLength = + (doc.properties.contentLength || 0) + block.size; + + await BlobsModel.upsert(this.convertBlobModelToDbModel(doc), { + transaction: t + }); + return doc.properties; + }); } public async listUncommittedBlockPersistencyChunks( @@ -2869,7 +3279,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { return new BlobReferredExtentsAsyncIterator(this); } - private async assertContainerExists( + protected async assertContainerExists( context: Context, account: string, container: string, @@ -2890,9 +3300,9 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { return findResult; } - private getModelValue(model: Model, key: string): T | undefined; - private getModelValue(model: Model, key: string, isRequired: true): T; - private getModelValue( + protected getModelValue(model: Model, key: string): T | undefined; + protected getModelValue(model: Model, key: string, isRequired: true): T; + protected getModelValue( model: Model, key: string, isRequired?: boolean @@ -2910,7 +3320,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { return value; } - private deserializeModelValue( + protected deserializeModelValue( model: Model, key: string, isRequired: boolean = false @@ -2931,7 +3341,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { return undefined; } - private serializeModelValue(value: any): string | undefined { + protected serializeModelValue(value: any): string | undefined { if (value === undefined || value === null) { return undefined; } @@ -2976,7 +3386,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { return arr; } - private convertDbModelToContainerModel( + protected convertDbModelToContainerModel( dbModel: ContainersModel ): ContainerModel { const accountName = this.getModelValue( @@ -3064,10 +3474,9 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { }; } - private convertDbModelToBlobModel(dbModel: BlobsModel): BlobModel { - const contentProperties: IBlobContentProperties = this.convertDbModelToBlobContentProperties( - dbModel - ); + protected convertDbModelToBlobModel(dbModel: BlobsModel): BlobModel { + const properties: Models.BlobPropertiesInternal = + this.convertDbModelToBlobProperties(dbModel); const lease = this.convertDbModelToLease(dbModel); @@ -3077,52 +3486,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { name: this.getModelValue(dbModel, "blobName", true), snapshot: this.getModelValue(dbModel, "snapshot", true), isCommitted: this.getModelValue(dbModel, "isCommitted", true), - properties: { - lastModified: this.getModelValue(dbModel, "lastModified", true), - etag: this.getModelValue(dbModel, "etag", true), - leaseDuration: lease.leaseDurationType, - creationTime: this.getModelValue(dbModel, "creationTime"), - leaseState: lease.leaseState, - leaseStatus: lease.leaseStatus, - accessTier: this.getModelValue( - dbModel, - "accessTier" - ), - accessTierInferred: this.getModelValue( - dbModel, - "accessTierInferred" - ), - accessTierChangeTime: this.getModelValue( - dbModel, - "accessTierChangeTime" - ), - blobSequenceNumber: this.getModelValue( - dbModel, - "blobSequenceNumber" - ), - blobType: this.getModelValue(dbModel, "blobType"), - contentMD5: contentProperties - ? this.restoreUint8Array(contentProperties.contentMD5) - : undefined, - contentDisposition: contentProperties - ? contentProperties.contentDisposition - : undefined, - contentEncoding: contentProperties - ? contentProperties.contentEncoding - : undefined, - contentLanguage: contentProperties - ? contentProperties.contentLanguage - : undefined, - contentLength: contentProperties - ? contentProperties.contentLength - : undefined, - contentType: contentProperties - ? contentProperties.contentType - : undefined, - cacheControl: contentProperties - ? contentProperties.cacheControl - : undefined - }, + properties: properties, leaseDurationSeconds: lease.leaseDurationSeconds, leaseBreakTime: lease.leaseBreakTime, leaseExpireTime: lease.leaseExpireTime, @@ -3132,70 +3496,68 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { dbModel, "committedBlocksInOrder" ), - metadata: this.deserializeModelValue(dbModel, "metadata") + pageRangesInOrder: this.deserializeModelValue(dbModel, "pageRangesInOrder"), + metadata: this.deserializeModelValue(dbModel, "metadata"), + isDirectory: this.getModelValue(dbModel, "isDirectory"), + permissions: this.getModelValue(dbModel, "permissions"), + acl: this.getModelValue(dbModel, "acl"), + owner: this.getModelValue(dbModel, "owner"), + group: this.getModelValue(dbModel, "group"), }; } - private convertBlobModelToDbModel(blob: BlobModel): object { - const contentProperties = this.convertBlobContentPropertiesToDbModel( - blob.properties - ); - + protected convertBlobModelToDbModel(blob: BlobModel): object { const lease = this.convertLeaseToDbModel(new BlobLeaseAdapter(blob)); return { accountName: blob.accountName, containerName: blob.containerName, blobName: blob.name, snapshot: blob.snapshot, - blobType: blob.properties.blobType, - blobSequenceNumber: blob.properties.blobSequenceNumber || null, isCommitted: blob.isCommitted, - lastModified: blob.properties.lastModified, - creationTime: blob.properties.creationTime || null, - etag: blob.properties.etag, - accessTier: blob.properties.accessTier || null, - accessTierChangeTime: blob.properties.accessTierChangeTime || null, - accessTierInferred: blob.properties.accessTierInferred || null, - leaseBreakExpireTime: blob.leaseBreakTime || null, - leaseExpireTime: blob.leaseExpireTime || null, - leaseId: blob.leaseId || null, - leasedurationNumber: blob.leaseDurationSeconds || null, - leaseDuration: blob.properties.leaseDuration || null, - leaseStatus: blob.properties.leaseStatus || null, - leaseState: blob.properties.leaseState || null, + properties: this.serializeModelValue(blob.properties) || null, ...lease, persistency: this.serializeModelValue(blob.persistency) || null, committedBlocksInOrder: this.serializeModelValue(blob.committedBlocksInOrder) || null, + pageRangesInOrder: + this.serializeModelValue(blob.pageRangesInOrder) || null, metadata: this.serializeModelValue(blob.metadata) || null, - ...contentProperties + isDirectory: blob.isDirectory, + permissions: blob.permissions, + acl: blob.acl, + owner: blob.owner, + group: blob.group }; } - private convertDbModelToBlobContentProperties( + private convertDbModelToBlobProperties( dbModel: BlobsModel - ): IBlobContentProperties { - return this.deserializeModelValue(dbModel, "contentProperties"); - } - - private convertBlobContentPropertiesToDbModel( - contentProperties: IBlobContentProperties - ): object { - return { - contentProperties: - this.serializeModelValue({ - contentLength: contentProperties.contentLength, - contentType: contentProperties.contentType, - contentEncoding: contentProperties.contentEncoding, - contentLanguage: contentProperties.contentLanguage, - contentMD5: contentProperties.contentMD5, - contentDisposition: contentProperties.contentDisposition, - cacheControl: contentProperties.cacheControl - }) || null + ): Models.BlobPropertiesInternal { + const propertiesDbModel = this.deserializeModelValue(dbModel, "properties"); + const properties: Models.BlobPropertiesInternal = { + ...propertiesDbModel, + lastModified: propertiesDbModel.lastModified + ? new Date(propertiesDbModel.lastModified) + : undefined, + copyCompletionTime: propertiesDbModel.copyCompletionTime + ? new Date(propertiesDbModel.copyCompletionTime) + : undefined, + creationTime: propertiesDbModel.creationTime + ? new Date(propertiesDbModel.creationTime) + : undefined, + deletedTime: propertiesDbModel.deletedTime + ? new Date(propertiesDbModel.deletedTime) + : undefined, + expiresOn: propertiesDbModel.expiresOn + ? new Date(propertiesDbModel.expiresOn) + : undefined, + contentMD5: this.restoreUint8Array(propertiesDbModel.contentMD5) }; + + return properties; } - private convertDbModelToLease(dbModel: ContainersModel | BlobsModel): ILease { + protected convertDbModelToLease(dbModel: ContainersModel | BlobsModel): ILease { const lease = (this.deserializeModelValue(dbModel, "lease") as ILease) || {}; @@ -3223,7 +3585,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { return { lease: leaseString }; } - private async getBlobWithLeaseUpdated( + protected async getBlobWithLeaseUpdated( account: string, container: string, blob: string, @@ -3324,4 +3686,70 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore { } return undefined; } + + private async destroyBlob( + account: string, + container: string, + blob: string | undefined, + snapshot: any, + t: Transaction + ): Promise { + const where: any = { + accountName: account, + containerName: container + }; + + if (blob !== undefined) where.blobName = blob; + if (snapshot !== undefined) where.snapshot = snapshot; + + if (this.softDelete) { + await BlobsModel.update( + { + deleting: literal("deleting + 1") + }, + { + where, + transaction: t + } + ); + } else { + await BlobsModel.destroy({ + where, + transaction: t + }); + } + } + + private async destroyBlock( + account: string, + container: string, + blob: string | undefined, + snapshot: any, + t: Transaction + ): Promise { + const where: any = { + accountName: account, + containerName: container + }; + + if (blob !== undefined) where.blobName = blob; + if (snapshot !== undefined) where.snapshot = snapshot; + + if (this.softDelete) { + await BlocksModel.update( + { + deleting: literal("deleting + 1") + }, + { + where, + transaction: t + } + ); + } else { + await BlocksModel.destroy({ + where, + transaction: t + }); + } + } } From 4e363b23f77f5a8787f05d5fcde04f05bffbfd51 Mon Sep 17 00:00:00 2001 From: Mahmoud Bahaa Date: Sat, 22 Apr 2023 04:10:57 +0200 Subject: [PATCH 3/4] * Minimal changes for blob end point to allow for extension in dfs endpoint * Added clearDb option to configurations in and set it to true in the test cases --- ChangeLog.md | 1 + README.md | 5 +- src/blob/BlobConfiguration.ts | 6 +- src/blob/BlobEnvironment.ts | 22 ++++++- src/blob/BlobServer.ts | 45 ++++++++------ src/blob/BlobServerFactory.ts | 55 ++++++++++++----- src/blob/IBlobEnvironment.ts | 5 ++ src/blob/SqlBlobConfiguration.ts | 12 ++-- src/blob/SqlBlobServer.ts | 43 +++++++------ .../authentication/AccountSASAuthenticator.ts | 57 ++++++++++-------- .../authentication/BlobSASAuthenticator.ts | 56 +++++++++-------- .../BlobSharedKeyAuthenticator.ts | 9 +-- .../authentication/BlobTokenAuthenticator.ts | 11 ++-- .../PublicAccessAuthenticator.ts | 30 ++++++---- src/blob/generated/MiddlewareFactory.ts | 3 +- src/blob/persistence/IBlobMetadataStore.ts | 20 ++++++- src/blob/persistence/LokiBlobMetadataStore.ts | 60 ++++++++++++------- src/blob/utils/constants.ts | 2 + src/common/ConfigurationBase.ts | 1 + src/common/Environment.ts | 22 ++++++- src/common/VSCEnvironment.ts | 8 +++ src/common/VSCServerManagerBlob.ts | 8 ++- src/common/utils/constants.ts | 17 +++--- 23 files changed, 322 insertions(+), 176 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 66a7cb588..57d699d74 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -8,6 +8,7 @@ Blob: - Fixed issue of: blob batch subresponse is slightly different from the on from Azure serivce, which causes exception in CPP SDK. - Fixed issue of: setMetadata API allows invalid metadata name with hyphen. +- Support Same features in SQL Metadata Store as Loki Metadata Store (support Blob Copy & Page Blob) ## 2023.03 Version 3.23.0 diff --git a/README.md b/README.md index e4d01c416..d44ec9ef5 100644 --- a/README.md +++ b/README.md @@ -473,13 +473,14 @@ Azurite will refresh customized account name and key from environment variable e By default, Azurite leverages [loki](https://github.com/techfort/LokiJS) as metadata database. However, as an in-memory database, loki limits Azurite's scalability and data persistency. -Set environment variable `AZURITE_DB=dialect://[username][:password][@]host:port/database` to make Azurite blob service switch to a SQL database based metadata storage, like MySql, SqlServer. +Set environment variable `AZURITE_DB=dialect://[username][:password][@]host:port/database` to make Azurite blob service switch to a SQL database based metadata storage, like MySql, SqlServer & PostgreSQL. For example, connect to MySql or SqlServer by set environment variables: ```bash set AZURITE_DB=mysql://username:password@localhost:3306/azurite_blob set AZURITE_DB=mssql://username:password@localhost:1024/azurite_blob +set AZURITE_DB=postgres://username:password@localhost:5432/azurite_blob ``` When Azurite starts with above environment variable, it connects to the configured database, and creates tables if not exist. @@ -487,8 +488,6 @@ This feature is in preview, when Azurite changes database table schema, you need > Note. Need to manually create database before starting Azurite instance. -> Note. Blob Copy & Page Blob are not supported by SQL based metadata implementation. - > Tips. Create database instance quickly with docker, for example `docker run --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:latest`. Grant external access and create database `azurite_blob` using `docker exec mysql mysql -u root -pmy-secret-pw -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION; FLUSH PRIVILEGES; create database azurite_blob;"`. Notice that, above commands are examples, you need to carefully define the access permissions in your production environment. ## HTTPS Setup diff --git a/src/blob/BlobConfiguration.ts b/src/blob/BlobConfiguration.ts index 9b9703cb4..24114f322 100644 --- a/src/blob/BlobConfiguration.ts +++ b/src/blob/BlobConfiguration.ts @@ -2,10 +2,8 @@ import ConfigurationBase from "../common/ConfigurationBase"; import { StoreDestinationArray } from "../common/persistence/IExtentStore"; import { DEFAULT_BLOB_EXTENT_LOKI_DB_PATH, - DEFAULT_BLOB_LISTENING_PORT, DEFAULT_BLOB_LOKI_DB_PATH, DEFAULT_BLOB_PERSISTENCE_ARRAY, - DEFAULT_BLOB_SERVER_HOST_NAME, DEFAULT_ENABLE_ACCESS_LOG, DEFAULT_ENABLE_DEBUG_LOG } from "./utils/constants"; @@ -24,8 +22,8 @@ import { */ export default class BlobConfiguration extends ConfigurationBase { public constructor( - host: string = DEFAULT_BLOB_SERVER_HOST_NAME, - port: number = DEFAULT_BLOB_LISTENING_PORT, + host: string, + port: number, public readonly metadataDBPath: string = DEFAULT_BLOB_LOKI_DB_PATH, public readonly extentDBPath: string = DEFAULT_BLOB_EXTENT_LOKI_DB_PATH, public readonly persistencePathArray: StoreDestinationArray = DEFAULT_BLOB_PERSISTENCE_ARRAY, diff --git a/src/blob/BlobEnvironment.ts b/src/blob/BlobEnvironment.ts index b5a54ebbb..a64f41294 100644 --- a/src/blob/BlobEnvironment.ts +++ b/src/blob/BlobEnvironment.ts @@ -5,11 +5,23 @@ import { dirname } from "path"; import IBlobEnvironment from "./IBlobEnvironment"; import { DEFAULT_BLOB_LISTENING_PORT, - DEFAULT_BLOB_SERVER_HOST_NAME + DEFAULT_BLOB_SERVER_HOST_NAME, + DEFAULT_DATA_LAKE_LISTENING_PORT, + DEFAULT_DATA_LAKE_SERVER_HOST_NAME } from "./utils/constants"; if (!(args as any).config.name) { args + .option( + ["", "datalakeHost"], + "Optional. Customize listening address for blob", + DEFAULT_DATA_LAKE_SERVER_HOST_NAME + ) + .option( + ["", "datalakePort"], + "Optional. Customize listening port for blob", + DEFAULT_DATA_LAKE_LISTENING_PORT + ) .option( ["", "blobHost"], "Optional. Customize listening address for blob", @@ -56,6 +68,14 @@ if (!(args as any).config.name) { export default class BlobEnvironment implements IBlobEnvironment { private flags = args.parse(process.argv); + public datalakeHost(): string | undefined { + return this.flags.datalakeHost; + } + + public datalakePort(): number | undefined { + return this.flags.datalakePort; + } + public blobHost(): string | undefined { return this.flags.blobHost; } diff --git a/src/blob/BlobServer.ts b/src/blob/BlobServer.ts index a70de8350..99d3b2ff3 100644 --- a/src/blob/BlobServer.ts +++ b/src/blob/BlobServer.ts @@ -18,10 +18,7 @@ import BlobRequestListenerFactory from "./BlobRequestListenerFactory"; import BlobGCManager from "./gc/BlobGCManager"; import IBlobMetadataStore from "./persistence/IBlobMetadataStore"; import LokiBlobMetadataStore from "./persistence/LokiBlobMetadataStore"; - -const BEFORE_CLOSE_MESSAGE = `Azurite Blob service is closing...`; -const BEFORE_CLOSE_MESSAGE_GC_ERROR = `Azurite Blob service is closing... Critical error happens during GC.`; -const AFTER_CLOSE_MESSAGE = `Azurite Blob service successfully closed`; +import { DEFAULT_BLOB_LISTENING_PORT, DEFAULT_BLOB_SERVER_HOST_NAME } from "./utils/constants"; /** * Default implementation of Azurite Blob HTTP server. @@ -42,6 +39,9 @@ export default class BlobServer extends ServerBase implements ICleaner { private readonly extentStore: IExtentStore; private readonly accountDataStore: IAccountDataStore; private readonly gcManager: IGCManager; + private readonly BEFORE_CLOSE_MESSAGE; + private readonly BEFORE_CLOSE_MESSAGE_GC_ERROR; + private readonly AFTER_CLOSE_MESSAGE; /** * Creates an instance of Server. @@ -49,9 +49,17 @@ export default class BlobServer extends ServerBase implements ICleaner { * @param {BlobConfiguration} configuration * @memberof Server */ - constructor(configuration?: BlobConfiguration) { + constructor( + configuration?: BlobConfiguration, + metadataStoreClass: any = LokiBlobMetadataStore, + requestListnerFactory: any = BlobRequestListenerFactory, + private readonly serviceName: string = "Blob" + ) { if (configuration === undefined) { - configuration = new BlobConfiguration(); + configuration = new BlobConfiguration( + DEFAULT_BLOB_SERVER_HOST_NAME, + DEFAULT_BLOB_LISTENING_PORT + ) } const host = configuration.host; @@ -72,7 +80,7 @@ export default class BlobServer extends ServerBase implements ICleaner { // We can change the persistency layer implementation by // creating a new XXXDataStore class implementing IBlobMetadataStore interface // and replace the default LokiBlobMetadataStore - const metadataStore: IBlobMetadataStore = new LokiBlobMetadataStore( + const metadataStore: IBlobMetadataStore = new metadataStoreClass( configuration.metadataDBPath // logger ); @@ -92,7 +100,7 @@ export default class BlobServer extends ServerBase implements ICleaner { // We can also change the HTTP framework here by // creating a new XXXListenerFactory implementing IRequestListenerFactory interface // and replace the default Express based request listener - const requestListenerFactory: IRequestListenerFactory = new BlobRequestListenerFactory( + const requestListenerFactory: IRequestListenerFactory = new requestListnerFactory( metadataStore, extentStore, accountDataStore, @@ -114,17 +122,20 @@ export default class BlobServer extends ServerBase implements ICleaner { extentStore, () => { // tslint:disable-next-line:no-console - console.log(BEFORE_CLOSE_MESSAGE_GC_ERROR); - logger.info(BEFORE_CLOSE_MESSAGE_GC_ERROR); + console.log(this.BEFORE_CLOSE_MESSAGE_GC_ERROR); + logger.info(this.BEFORE_CLOSE_MESSAGE_GC_ERROR); this.close().then(() => { // tslint:disable-next-line:no-console - console.log(AFTER_CLOSE_MESSAGE); - logger.info(AFTER_CLOSE_MESSAGE); + console.log(this.AFTER_CLOSE_MESSAGE); + logger.info(this.AFTER_CLOSE_MESSAGE); }); }, logger ); + this.BEFORE_CLOSE_MESSAGE = `Azurite ${serviceName} service is closing...`; + this.BEFORE_CLOSE_MESSAGE_GC_ERROR = `Azurite ${serviceName} service is closing... Critical error happens during GC.`; + this.AFTER_CLOSE_MESSAGE = `Azurite ${serviceName} service successfully closed`; this.metadataStore = metadataStore; this.extentMetadataStore = extentMetadataStore; this.extentStore = extentStore; @@ -158,11 +169,11 @@ export default class BlobServer extends ServerBase implements ICleaner { } return; } - throw Error(`Cannot clean up blob server in status ${this.getStatus()}.`); + throw Error(`Cannot clean up ${this.serviceName} server in status ${this.getStatus()}.`); } protected async beforeStart(): Promise { - const msg = `Azurite Blob service is starting on ${this.host}:${this.port}`; + const msg = `Azurite ${this.serviceName} service is starting on ${this.host}:${this.port}`; logger.info(msg); if (this.accountDataStore !== undefined) { @@ -187,12 +198,12 @@ export default class BlobServer extends ServerBase implements ICleaner { } protected async afterStart(): Promise { - const msg = `Azurite Blob service successfully listens on ${this.getHttpServerAddress()}`; + const msg = `Azurite ${this.serviceName} service successfully listens on ${this.getHttpServerAddress()}`; logger.info(msg); } protected async beforeClose(): Promise { - logger.info(BEFORE_CLOSE_MESSAGE); + logger.info(this.BEFORE_CLOSE_MESSAGE); } protected async afterClose(): Promise { @@ -216,6 +227,6 @@ export default class BlobServer extends ServerBase implements ICleaner { await this.accountDataStore.close(); } - logger.info(AFTER_CLOSE_MESSAGE); + logger.info(this.AFTER_CLOSE_MESSAGE); } } diff --git a/src/blob/BlobServerFactory.ts b/src/blob/BlobServerFactory.ts index fb076a65d..7a08b542a 100644 --- a/src/blob/BlobServerFactory.ts +++ b/src/blob/BlobServerFactory.ts @@ -7,16 +7,43 @@ import BlobServer from "./BlobServer"; import IBlobEnvironment from "./IBlobEnvironment"; import SqlBlobConfiguration from "./SqlBlobConfiguration"; import SqlBlobServer from "./SqlBlobServer"; -import { DEFAULT_BLOB_PERSISTENCE_PATH } from "./utils/constants"; +import { DEFAULT_BLOB_LISTENING_PORT, DEFAULT_BLOB_PERSISTENCE_PATH, DEFAULT_BLOB_SERVER_HOST_NAME } from "./utils/constants"; import { DEFAULT_BLOB_EXTENT_LOKI_DB_PATH, DEFAULT_BLOB_LOKI_DB_PATH, DEFAULT_BLOB_PERSISTENCE_ARRAY } from "./utils/constants"; +import { StoreDestinationArray } from "../common/persistence/IExtentStore"; export class BlobServerFactory { public async createServer( blobEnvironment?: IBlobEnvironment + ): Promise { + return this.createActualServer( + blobEnvironment, + DEFAULT_BLOB_PERSISTENCE_ARRAY, + DEFAULT_BLOB_PERSISTENCE_PATH, + "AZURITE_DB", + DEFAULT_BLOB_SERVER_HOST_NAME, + DEFAULT_BLOB_LISTENING_PORT, + DEFAULT_BLOB_LOKI_DB_PATH, + DEFAULT_BLOB_EXTENT_LOKI_DB_PATH, + SqlBlobServer, + BlobServer + ); + } + + protected async createActualServer( + blobEnvironment: IBlobEnvironment | undefined, + persistenceArray: StoreDestinationArray, + persistencePath: string, + dbKey: string, + defaultHost: string, + defaultPort: number, + defaultLokiDBPath: string, + defaultExtentLokiDBPath: string, + sqlSeverClass: any, + blobServerClass: any, ): Promise { // TODO: Check it's in Visual Studio Code environment or not const isVSC = false; @@ -32,22 +59,22 @@ export class BlobServerFactory { ); } - DEFAULT_BLOB_PERSISTENCE_ARRAY[0].locationPath = join( + persistenceArray[0].locationPath = join( location, - DEFAULT_BLOB_PERSISTENCE_PATH + persistencePath ); // TODO: Check we need to create blob server against SQL or Loki - const databaseConnectionString = process.env.AZURITE_DB; + const databaseConnectionString = process.env[dbKey]; const isSQL = databaseConnectionString !== undefined; if (isSQL) { const config = new SqlBlobConfiguration( - env.blobHost(), - env.blobPort(), + env.blobHost() || defaultHost, + env.blobPort() || defaultPort, databaseConnectionString!, DEFAULT_SQL_OPTIONS, - DEFAULT_BLOB_PERSISTENCE_ARRAY, + persistenceArray, !env.silent(), undefined, debugFilePath !== undefined, @@ -61,14 +88,14 @@ export class BlobServerFactory { env.disableProductStyleUrl() ); - return new SqlBlobServer(config); + return new sqlSeverClass(config); } else { const config = new BlobConfiguration( - env.blobHost(), - env.blobPort(), - join(location, DEFAULT_BLOB_LOKI_DB_PATH), - join(location, DEFAULT_BLOB_EXTENT_LOKI_DB_PATH), - DEFAULT_BLOB_PERSISTENCE_ARRAY, + env.blobHost() || defaultHost, + env.blobPort() || defaultPort, + join(location, defaultLokiDBPath), + join(location, defaultExtentLokiDBPath), + persistenceArray, !env.silent(), undefined, debugFilePath !== undefined, @@ -81,7 +108,7 @@ export class BlobServerFactory { env.oauth(), env.disableProductStyleUrl() ); - return new BlobServer(config); + return new blobServerClass(config); } } else { // TODO: Add BlobServer construction in VSC diff --git a/src/blob/IBlobEnvironment.ts b/src/blob/IBlobEnvironment.ts index 822e770e8..87e6696f4 100644 --- a/src/blob/IBlobEnvironment.ts +++ b/src/blob/IBlobEnvironment.ts @@ -1,6 +1,11 @@ export default interface IBlobEnvironment { + //dfs + datalakeHost(): string | undefined; + datalakePort(): number | undefined; + //blob blobHost(): string | undefined; blobPort(): number | undefined; + //common location(): Promise; silent(): boolean; loose(): boolean; diff --git a/src/blob/SqlBlobConfiguration.ts b/src/blob/SqlBlobConfiguration.ts index a6e8b0586..fe613fa2e 100644 --- a/src/blob/SqlBlobConfiguration.ts +++ b/src/blob/SqlBlobConfiguration.ts @@ -4,9 +4,7 @@ import ConfigurationBase from "../common/ConfigurationBase"; import { StoreDestinationArray } from "../common/persistence/IExtentStore"; import { DEFAULT_SQL_OPTIONS } from "../common/utils/constants"; import { - DEFAULT_BLOB_LISTENING_PORT, DEFAULT_BLOB_PERSISTENCE_ARRAY, - DEFAULT_BLOB_SERVER_HOST_NAME, DEFAULT_ENABLE_ACCESS_LOG, DEFAULT_ENABLE_DEBUG_LOG } from "./utils/constants"; @@ -20,8 +18,8 @@ import { */ export default class SqlBlobConfiguration extends ConfigurationBase { public constructor( - host: string = DEFAULT_BLOB_SERVER_HOST_NAME, - port: number = DEFAULT_BLOB_LISTENING_PORT, + host: string, + port: number, public readonly sqlURL: string, public readonly sequelizeOptions: SequelizeOptions = DEFAULT_SQL_OPTIONS, public readonly persistenceArray: StoreDestinationArray = DEFAULT_BLOB_PERSISTENCE_ARRAY, @@ -35,7 +33,8 @@ export default class SqlBlobConfiguration extends ConfigurationBase { key: string = "", pwd: string = "", oauth?: string, - disableProductStyleUrl: boolean = false + disableProductStyleUrl: boolean = false, + clearDB: boolean = false ) { super( host, @@ -50,7 +49,8 @@ export default class SqlBlobConfiguration extends ConfigurationBase { key, pwd, oauth, - disableProductStyleUrl + disableProductStyleUrl, + clearDB ); } } diff --git a/src/blob/SqlBlobServer.ts b/src/blob/SqlBlobServer.ts index c0e07e6d3..352e1b5c4 100644 --- a/src/blob/SqlBlobServer.ts +++ b/src/blob/SqlBlobServer.ts @@ -18,10 +18,6 @@ import IBlobMetadataStore from "./persistence/IBlobMetadataStore"; import SqlBlobMetadataStore from "./persistence/SqlBlobMetadataStore"; import SqlBlobConfiguration from "./SqlBlobConfiguration"; -const BEFORE_CLOSE_MESSAGE = `Azurite Blob service is closing...`; -const BEFORE_CLOSE_MESSAGE_GC_ERROR = `Azurite Blob service is closing... Critical error happens during GC.`; -const AFTER_CLOSE_MESSAGE = `Azurite Blob service successfully closed`; - /** * Default implementation of Azurite Blob HTTP server. * This implementation provides a HTTP service based on express framework and LokiJS in memory database. @@ -41,6 +37,9 @@ export default class SqlBlobServer extends ServerBase { private readonly extentStore: IExtentStore; private readonly accountDataStore: IAccountDataStore; private readonly gcManager: IGCManager; + private readonly BEFORE_CLOSE_MESSAGE; + private readonly BEFORE_CLOSE_MESSAGE_GC_ERROR; + private readonly AFTER_CLOSE_MESSAGE; /** * Creates an instance of Server. @@ -48,7 +47,12 @@ export default class SqlBlobServer extends ServerBase { * @param {BlobConfiguration} configuration * @memberof Server */ - constructor(configuration: SqlBlobConfiguration) { + constructor( + configuration: SqlBlobConfiguration, + metadataStoreClass: any = SqlBlobMetadataStore, + requestListnerFactory: any = BlobRequestListenerFactory, + private readonly serviceName: string = "Blob" + ) { const host = configuration.host; const port = configuration.port; @@ -64,9 +68,11 @@ export default class SqlBlobServer extends ServerBase { httpServer = http.createServer(); } - const metadataStore: IBlobMetadataStore = new SqlBlobMetadataStore( + const metadataStore: IBlobMetadataStore = new metadataStoreClass( configuration.sqlURL, - configuration.sequelizeOptions + configuration.sequelizeOptions, + configuration.clearDB, + process.env.IS_DATALAKE !== "true", ); const extentMetadataStore: IExtentMetadataStore = new SqlExtentMetadataStore( @@ -87,7 +93,7 @@ export default class SqlBlobServer extends ServerBase { // We can also change the HTTP framework here by // creating a new XXXListenerFactory implementing IRequestListenerFactory interface // and replace the default Express based request listener - const requestListenerFactory: IRequestListenerFactory = new BlobRequestListenerFactory( + const requestListenerFactory: IRequestListenerFactory = new requestListnerFactory( metadataStore, extentStore, accountDataStore, @@ -109,19 +115,22 @@ export default class SqlBlobServer extends ServerBase { extentStore, error => { // tslint:disable-next-line:no-console - console.log(BEFORE_CLOSE_MESSAGE_GC_ERROR, error); - logger.info(BEFORE_CLOSE_MESSAGE_GC_ERROR + JSON.stringify(error)); + console.log(this.BEFORE_CLOSE_MESSAGE_GC_ERROR, error); + logger.info(this.BEFORE_CLOSE_MESSAGE_GC_ERROR + JSON.stringify(error)); // TODO: Bring this back when GC based on SQL implemented this.close().then(() => { // tslint:disable-next-line:no-console - console.log(AFTER_CLOSE_MESSAGE); - logger.info(AFTER_CLOSE_MESSAGE); + console.log(this.AFTER_CLOSE_MESSAGE); + logger.info(this.AFTER_CLOSE_MESSAGE); }); }, logger ); + this.BEFORE_CLOSE_MESSAGE = `Azurite ${serviceName} service is closing...`; + this.BEFORE_CLOSE_MESSAGE_GC_ERROR = `Azurite ${serviceName} service is closing... Critical error happens during GC.`; + this.AFTER_CLOSE_MESSAGE = `Azurite ${serviceName} service successfully closed`; this.metadataStore = metadataStore; this.extentMetadataStore = extentMetadataStore; this.extentStore = extentStore; @@ -154,11 +163,11 @@ export default class SqlBlobServer extends ServerBase { } return; } - throw Error(`Cannot clean up blob server in status ${this.getStatus()}.`); + throw Error(`Cannot clean up ${this.serviceName} server in status ${this.getStatus()}.`); } protected async beforeStart(): Promise { - const msg = `Azurite Blob service is starting on ${this.host}:${this.port}`; + const msg = `Azurite ${this.serviceName} service is starting on ${this.host}:${this.port}`; logger.info(msg); if (this.accountDataStore !== undefined) { @@ -183,12 +192,12 @@ export default class SqlBlobServer extends ServerBase { } protected async afterStart(): Promise { - const msg = `Azurite Blob service successfully listens on ${this.getHttpServerAddress()}`; + const msg = `Azurite ${this.serviceName} service successfully listens on ${this.getHttpServerAddress()}`; logger.info(msg); } protected async beforeClose(): Promise { - logger.info(BEFORE_CLOSE_MESSAGE); + logger.info(this.BEFORE_CLOSE_MESSAGE); } protected async afterClose(): Promise { @@ -212,6 +221,6 @@ export default class SqlBlobServer extends ServerBase { await this.accountDataStore.close(); } - logger.info(AFTER_CLOSE_MESSAGE); + logger.info(this.AFTER_CLOSE_MESSAGE); } } diff --git a/src/blob/authentication/AccountSASAuthenticator.ts b/src/blob/authentication/AccountSASAuthenticator.ts index 0cce278b1..3ecef6f26 100644 --- a/src/blob/authentication/AccountSASAuthenticator.ts +++ b/src/blob/authentication/AccountSASAuthenticator.ts @@ -2,7 +2,6 @@ import IAccountDataStore from "../../common/IAccountDataStore"; import ILogger from "../../common/ILogger"; import StorageErrorFactory from "../errors/StorageErrorFactory"; import { BlobType } from "../generated/artifacts/models"; -import Operation from "../generated/artifacts/operation"; import Context from "../generated/Context"; import IRequest from "../generated/IRequest"; import IBlobMetadataStore from "../persistence/IBlobMetadataStore"; @@ -11,12 +10,13 @@ import { generateAccountSASSignature, IAccountSASSignatureValues } from "../../common/authentication/IAccountSASSignatureValues"; -import IAuthenticator from "./IAuthenticator"; -import OPERATION_ACCOUNT_SAS_PERMISSIONS from "./OperationAccountSASPermission"; import StrictModelNotSupportedError from "../errors/StrictModelNotSupportedError"; import { AUTHENTICATION_BEARERTOKEN_REQUIRED } from "../utils/constants"; +import Operation from "../generated/artifacts/operation"; +import OPERATION_ACCOUNT_SAS_PERMISSIONS, { OperationAccountSASPermission } from "./OperationAccountSASPermission"; +import IAuthenticator from "./IAuthenticator"; -export default class AccountSASAuthenticator implements IAuthenticator { +export default class AccountSASAuthenticator implements IAuthenticator { public constructor( private readonly accountDataStore: IAccountDataStore, private readonly blobMetadataStore: IBlobMetadataStore, @@ -198,14 +198,7 @@ export default class AccountSASAuthenticator implements IAuthenticator { ); } - const operation = context.operation; - if (operation === undefined) { - throw new Error( - // tslint:disable-next-line:max-line-length - `AccountSASAuthenticator:validate() operation shouldn't be undefined. Please make sure DispatchMiddleware is hooked before authentication related middleware.` - ); - } - else if (operation === Operation.Service_GetUserDelegationKey) { + if (context.operation === Operation.Service_GetUserDelegationKey) { this.logger.info( `AccountSASAuthenticator:validate() Service_GetUserDelegationKey requires OAuth credentials" }.`, @@ -215,19 +208,17 @@ export default class AccountSASAuthenticator implements IAuthenticator { AUTHENTICATION_BEARERTOKEN_REQUIRED); } - const accountSASPermission = OPERATION_ACCOUNT_SAS_PERMISSIONS.get( - operation - ); + const accountSASPermission = this.getOperationAccountSASPermission(context); this.logger.debug( `AccountSASAuthenticator:validate() Got permission requirements for operation ${ - Operation[operation] + this.getOperationString(context) } - ${JSON.stringify(accountSASPermission)}`, context.contextId ); if (accountSASPermission === undefined) { throw new Error( // tslint:disable-next-line:max-line-length - `AccountSASAuthenticator:validate() OPERATION_ACCOUNT_SAS_PERMISSIONS doesn't have configuration for operation ${Operation[operation]}'s account SAS permission.` + `AccountSASAuthenticator:validate() OPERATION_ACCOUNT_SAS_PERMISSIONS doesn't have configuration for operation ${this.getOperationString(context)}'s account SAS permission.` ); } @@ -254,15 +245,9 @@ export default class AccountSASAuthenticator implements IAuthenticator { // If page blob exists, then permission must be Write only // If append blob exists, then permission must be Write only // If copy destination blob exists, then permission must be Write only - if ( - operation === Operation.BlockBlob_Upload || - operation === Operation.PageBlob_Create || - operation === Operation.AppendBlob_Create || - operation === Operation.Blob_StartCopyFromURL || - operation === Operation.Blob_CopyFromURL - ) { + if (this.isSpecialPermissions(context)) { this.logger.info( - `AccountSASAuthenticator:validate() For ${Operation[operation]}, if blob exists, the permission must be Write.`, + `AccountSASAuthenticator:validate() For ${this.getOperationString(context)}, if blob exists, the permission must be Write.`, context.contextId ); @@ -389,4 +374,26 @@ export default class AccountSASAuthenticator implements IAuthenticator { return true; } + + protected isSpecialPermissions(context: Context): boolean { + const operation: Operation = context.operation!; + return operation === Operation.BlockBlob_Upload || + operation === Operation.PageBlob_Create || + operation === Operation.AppendBlob_Create || + operation === Operation.Blob_StartCopyFromURL || + operation === Operation.Blob_CopyFromURL + } + + protected getOperationAccountSASPermission( + context: Context + ): OperationAccountSASPermission | undefined { + return OPERATION_ACCOUNT_SAS_PERMISSIONS.get(context.operation!); + } + + protected getOperationString(context: Context): string { + return Operation[context.operation!] + } } + + + diff --git a/src/blob/authentication/BlobSASAuthenticator.ts b/src/blob/authentication/BlobSASAuthenticator.ts index d61f43ce8..7668436e9 100644 --- a/src/blob/authentication/BlobSASAuthenticator.ts +++ b/src/blob/authentication/BlobSASAuthenticator.ts @@ -20,7 +20,8 @@ import { } from "./IBlobSASSignatureValues"; import { OPERATION_BLOB_SAS_BLOB_PERMISSIONS, - OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS + OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS, + OperationBlobSASPermission } from "./OperationBlobSASPermission"; export default class BlobSASAuthenticator implements IAuthenticator { @@ -363,15 +364,8 @@ export default class BlobSASAuthenticator implements IAuthenticator { context.contextId! ); } - - const operation = context.operation; - if (operation === undefined) { - throw new Error( - // tslint:disable-next-line:max-line-length - `BlobSASAuthenticator:validate() Operation shouldn't be undefined. Please make sure DispatchMiddleware is hooked before authentication related middleware.` - ); - } - else if (operation === Operation.Service_GetUserDelegationKey) { + + else if (context.operation === Operation.Service_GetUserDelegationKey) { this.logger.info( `BlobSASAuthenticator:validate() Service_GetUserDelegationKey requires OAuth credentials" }.`, @@ -381,14 +375,10 @@ export default class BlobSASAuthenticator implements IAuthenticator { AUTHENTICATION_BEARERTOKEN_REQUIRED); } - const blobSASPermission = - resource === BlobSASResourceType.Blob - ? OPERATION_BLOB_SAS_BLOB_PERMISSIONS.get(operation) - : OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.get(operation); - + const blobSASPermission = this.getOperationBlobSASPermission(resource, context); this.logger.debug( `BlobSASAuthenticator:validate() Got permission requirements for operation ${ - Operation[operation] + this.getOperationString(context) } - ${JSON.stringify(blobSASPermission)}`, context.contextId ); @@ -400,7 +390,7 @@ export default class BlobSASAuthenticator implements IAuthenticator { ? "OPERATION_BLOB_SAS_BLOB_PERMISSIONS" : "OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS" } doesn't have configuration for operation ${ - Operation[operation] + this.getOperationString(context) }'s blob service SAS permission.` ); } @@ -416,15 +406,9 @@ export default class BlobSASAuthenticator implements IAuthenticator { // If page blob exists, then permission must be Write only // If append blob exists, then permission must be Write only // If copy destination blob exists, then permission must be Write only - if ( - operation === Operation.BlockBlob_Upload || - operation === Operation.PageBlob_Create || - operation === Operation.AppendBlob_Create || - operation === Operation.Blob_StartCopyFromURL || - operation === Operation.Blob_CopyFromURL - ) { + if (this.isSpecialPermissions(context)) { this.logger.info( - `BlobSASAuthenticator:validate() For ${Operation[operation]}, if blob exists, the permission must be Write.`, + `BlobSASAuthenticator:validate() For ${this.getOperationString(context)}, if blob exists, the permission must be Write.`, context.contextId ); @@ -624,4 +608,26 @@ export default class BlobSASAuthenticator implements IAuthenticator { return true; } + + protected isSpecialPermissions(context: Context): boolean { + const operation: Operation = context.operation!; + return operation === Operation.BlockBlob_Upload || + operation === Operation.PageBlob_Create || + operation === Operation.AppendBlob_Create || + operation === Operation.Blob_StartCopyFromURL || + operation === Operation.Blob_CopyFromURL + } + + protected getOperationBlobSASPermission( + resource: BlobSASResourceType, + context: Context + ): OperationBlobSASPermission | undefined { + return resource === BlobSASResourceType.Blob + ? OPERATION_BLOB_SAS_BLOB_PERMISSIONS.get(context.operation!) + : OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.get(context.operation!); + } + + protected getOperationString(context: Context): string { + return Operation[context.operation!] + } } diff --git a/src/blob/authentication/BlobSharedKeyAuthenticator.ts b/src/blob/authentication/BlobSharedKeyAuthenticator.ts index f762d5438..5ce998281 100644 --- a/src/blob/authentication/BlobSharedKeyAuthenticator.ts +++ b/src/blob/authentication/BlobSharedKeyAuthenticator.ts @@ -57,14 +57,7 @@ export default class BlobSharedKeyAuthenticator implements IAuthenticator { ); } - const operation = context.operation; - if (operation === undefined) { - throw new Error( - // tslint:disable-next-line:max-line-length - `BlobSharedKeyAuthenticator:validate() Operation shouldn't be undefined. Please make sure DispatchMiddleware is hooked before authentication related middleware.` - ); - } - else if (operation === Operation.Service_GetUserDelegationKey) { + if (context.operation === Operation.Service_GetUserDelegationKey) { this.logger.info( `BlobSharedKeyAuthenticator:validate() Service_GetUserDelegationKey requires OAuth credentials" }.`, diff --git a/src/blob/authentication/BlobTokenAuthenticator.ts b/src/blob/authentication/BlobTokenAuthenticator.ts index d81b9d82e..fb6d3a6d1 100644 --- a/src/blob/authentication/BlobTokenAuthenticator.ts +++ b/src/blob/authentication/BlobTokenAuthenticator.ts @@ -217,14 +217,13 @@ export default class BlobTokenAuthenticator implements IAuthenticator { ); } - const blobContext = context as BlobStorageContext; let audMatch = false; let m; - for (const regex of VALID_BLOB_AUDIENCES) { + for (const regex of this.getValidAudiences()) { m = regex.exec(aud); if (m !== null) { if (m[0] === aud) { - if (m[1] !== undefined && m[1] !== blobContext.account) { + if (m[1] !== undefined && m[1] !== context.context.account) { // If account name doesn't match for fine grained audiance break; } @@ -246,8 +245,12 @@ export default class BlobTokenAuthenticator implements IAuthenticator { this.logger.info( `BlobTokenAuthenticator:authenticateBasic() Validation against token authentication successfully.`, - blobContext.contextId + context.contextId ); return true; } + + protected getValidAudiences(): RegExp[] { + return VALID_BLOB_AUDIENCES; + } } diff --git a/src/blob/authentication/PublicAccessAuthenticator.ts b/src/blob/authentication/PublicAccessAuthenticator.ts index 07dc339f3..d0214c773 100644 --- a/src/blob/authentication/PublicAccessAuthenticator.ts +++ b/src/blob/authentication/PublicAccessAuthenticator.ts @@ -85,26 +85,18 @@ export default class PublicAccessAuthenticator implements IAuthenticator { context.contextId ); - const operation = context.operation; - if (operation === undefined) { - throw new Error( - // tslint:disable-next-line:max-line-length - `PublicAccessAuthenticator:validate() Operation shouldn't be undefined. Please make sure DispatchMiddleware is hooked before authentication related middleware.` - ); - } - if (containerPublicAccessType === PublicAccessType.Container) { - if (CONTAINER_PUBLIC_READ_OPERATIONS.has(operation)) { + if (this.isContainerPublicReadOperation(context)) { this.logger.debug( - `PublicAccessAuthenticator:validate() Operation ${Operation[operation]} is in container level public access list. Validation passed.`, + `PublicAccessAuthenticator:validate() Operation ${this.getOperationString(context)} is in container level public access list. Validation passed.`, context.contextId ); return true; } } else if (containerPublicAccessType === PublicAccessType.Blob) { - if (BLOB_PUBLIC_READ_OPERATIONS.has(operation)) { + if (this.isBlobPublicReadOperation(context)) { this.logger.debug( - `PublicAccessAuthenticator:validate() Operation ${Operation[operation]} is in blob level public access list. Validation passed.`, + `PublicAccessAuthenticator:validate() Operation ${this.getOperationString(context)} is in blob level public access list. Validation passed.`, context.contextId ); return true; @@ -116,7 +108,7 @@ export default class PublicAccessAuthenticator implements IAuthenticator { } this.logger.debug( - `PublicAccessAuthenticator:validate() Operation ${Operation[operation]} is not in container neither blob level public access list. Validation failed.`, + `PublicAccessAuthenticator:validate() Operation ${this.getOperationString(context)} is not in container neither blob level public access list. Validation failed.`, context.contextId ); @@ -146,4 +138,16 @@ export default class PublicAccessAuthenticator implements IAuthenticator { return undefined; } } + + protected isContainerPublicReadOperation(context: Context): boolean { + return CONTAINER_PUBLIC_READ_OPERATIONS.has(context.operation!) + } + + protected isBlobPublicReadOperation(context: Context): boolean { + return BLOB_PUBLIC_READ_OPERATIONS.has(context.operation!); + } + + protected getOperationString(context: Context): string { + return Operation[context.operation!] + } } diff --git a/src/blob/generated/MiddlewareFactory.ts b/src/blob/generated/MiddlewareFactory.ts index 048a63f0e..4b4697300 100644 --- a/src/blob/generated/MiddlewareFactory.ts +++ b/src/blob/generated/MiddlewareFactory.ts @@ -1,4 +1,3 @@ -import IHandlers from './handlers/IHandlers'; import ILogger from './utils/ILogger'; export type Callback = (...args: any[]) => any; @@ -63,7 +62,7 @@ export default abstract class MiddlewareFactory { * @returns {MiddlewareTypes} * @memberof MiddlewareFactory */ - public abstract createHandlerMiddleware(handlers: IHandlers): MiddlewareTypes; + public abstract createHandlerMiddleware(handlers: any): MiddlewareTypes; /** * SerializerMiddleware is the 4st middleware should be used among other generated middleware. diff --git a/src/blob/persistence/IBlobMetadataStore.ts b/src/blob/persistence/IBlobMetadataStore.ts index 429340c78..16f477d95 100644 --- a/src/blob/persistence/IBlobMetadataStore.ts +++ b/src/blob/persistence/IBlobMetadataStore.ts @@ -35,24 +35,32 @@ interface IContainerAdditionalProperties { leaseExpireTime?: Date; leaseBreakTime?: Date; containerAcl?: Models.SignedIdentifier[]; + fileSystemProperties?: string; +} + +interface IFileSystemAdditionalProperties { + fileSystemProperties?: string; } export type ContainerModel = Models.ContainerItem & - IContainerAdditionalProperties; + IContainerAdditionalProperties & + IFileSystemAdditionalProperties; export interface IContainerMetadata { [propertyName: string]: string; } // The response model for getContainerProperties. -export type GetContainerPropertiesResponse = Models.ContainerItem; +export type GetContainerPropertiesResponse = Models.ContainerItem & + IFileSystemAdditionalProperties; // The response for getContainerAccessPolicy. interface IGetContainerAccessPolicyResponse { properties: Models.ContainerProperties; containerAcl?: Models.SignedIdentifier[]; } -export type GetContainerAccessPolicyResponse = IGetContainerAccessPolicyResponse; +export type GetContainerAccessPolicyResponse = + IGetContainerAccessPolicyResponse; // The params for setContainerAccessPolicy. interface ISetContainerAccessPolicyOptions { @@ -133,6 +141,12 @@ interface IBlobAdditionalProperties { leaseId?: string; leaseExpireTime?: Date; leaseBreakTime?: Date; + //Dfs properties + isDirectory?: boolean; + permissions?: string; + owner?: string; + group?: string; + acl?: string; } export type BlobModel = IBlobAdditionalProperties & diff --git a/src/blob/persistence/LokiBlobMetadataStore.ts b/src/blob/persistence/LokiBlobMetadataStore.ts index b7ecb7658..623100d78 100644 --- a/src/blob/persistence/LokiBlobMetadataStore.ts +++ b/src/blob/persistence/LokiBlobMetadataStore.ts @@ -92,15 +92,15 @@ import PageWithDelimiter from "./PageWithDelimiter"; */ export default class LokiBlobMetadataStore implements IBlobMetadataStore, IGCExtentProvider { - private readonly db: Loki; + protected readonly db: Loki; private initialized: boolean = false; private closed: boolean = true; private readonly SERVICES_COLLECTION = "$SERVICES_COLLECTION$"; - private readonly CONTAINERS_COLLECTION = "$CONTAINERS_COLLECTION$"; - private readonly BLOBS_COLLECTION = "$BLOBS_COLLECTION$"; - private readonly BLOCKS_COLLECTION = "$BLOCKS_COLLECTION$"; + protected readonly CONTAINERS_COLLECTION = "$CONTAINERS_COLLECTION$"; + protected readonly BLOBS_COLLECTION = "$BLOBS_COLLECTION$"; + protected readonly BLOCKS_COLLECTION = "$BLOCKS_COLLECTION$"; private readonly pageBlobRangesManager = new PageBlobRangesManager(); @@ -418,7 +418,8 @@ export default class LokiBlobMetadataStore const res: GetContainerPropertiesResponse = { name: container, properties: doc.properties, - metadata: doc.metadata + metadata: doc.metadata, + fileSystemProperties: doc.fileSystemProperties, }; return res; @@ -1049,7 +1050,12 @@ export default class LokiBlobMetadataStore ? undefined : doc.committedBlocksInOrder.slice(), persistency: - doc.persistency === undefined ? undefined : { ...doc.persistency } + doc.persistency === undefined ? undefined : { ...doc.persistency }, + isDirectory: doc.isDirectory, + permissions: doc.permissions, + acl: doc.acl, + owner: doc.owner, + group: doc.group }; new BlobLeaseSyncer(snapshotBlob).sync({ @@ -1912,7 +1918,12 @@ export default class LokiBlobMetadataStore leaseBreakTime: destBlob !== undefined ? destBlob.leaseBreakTime : undefined, committedBlocksInOrder: sourceBlob.committedBlocksInOrder, - persistency: sourceBlob.persistency + persistency: sourceBlob.persistency, + isDirectory: sourceBlob.isDirectory, + permissions: sourceBlob.permissions, + acl: sourceBlob.acl, + owner: sourceBlob.owner, + group: sourceBlob.group }; if ( @@ -2098,7 +2109,12 @@ export default class LokiBlobMetadataStore leaseBreakTime: destBlob !== undefined ? destBlob.leaseBreakTime : undefined, committedBlocksInOrder: sourceBlob.committedBlocksInOrder, - persistency: sourceBlob.persistency + persistency: sourceBlob.persistency, + isDirectory: sourceBlob.isDirectory, + permissions: sourceBlob.permissions, + acl: sourceBlob.acl, + owner: sourceBlob.owner, + group: sourceBlob.group }; if ( @@ -3000,12 +3016,12 @@ export default class LokiBlobMetadataStore * LokiJS will persist Uint8Array into Object. * This method will restore object to Uint8Array. * - * @private + * @protected * @param {*} obj * @returns {(Uint8Array | undefined)} * @memberof LokiBlobMetadataStore */ - private restoreUint8Array(obj: any): Uint8Array | undefined { + protected restoreUint8Array(obj: any): Uint8Array | undefined { if (typeof obj !== "object") { return undefined; } @@ -3037,12 +3053,12 @@ export default class LokiBlobMetadataStore /** * Escape a string to be used as a regex. * - * @private + * @protected * @param {string} regex * @returns {string} * @memberof LokiBlobMetadataStore */ - private escapeRegex(regex: string): string { + protected escapeRegex(regex: string): string { return regex.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&"); } @@ -3063,14 +3079,14 @@ export default class LokiBlobMetadataStore * Updated lease related properties according to current time. * Will throw ContainerNotFound storage error if container doesn't exist. * - * @private + * @protected * @param {string} account * @param {string} container * @param {Context} context * @returns {Promise} * @memberof LokiBlobMetadataStore */ - private async getContainerWithLeaseUpdated( + protected async getContainerWithLeaseUpdated( account: string, container: string, context: Context, @@ -3082,7 +3098,7 @@ export default class LokiBlobMetadataStore * Updated lease related properties according to current time. * Will NOT throw ContainerNotFound storage error if container doesn't exist. * - * @private + * @protected * @param {string} account * @param {string} container * @param {Context} context @@ -3090,14 +3106,14 @@ export default class LokiBlobMetadataStore * @returns {(Promise)} * @memberof LokiBlobMetadataStore */ - private async getContainerWithLeaseUpdated( + protected async getContainerWithLeaseUpdated( account: string, container: string, context: Context, forceExist: false ): Promise; - private async getContainerWithLeaseUpdated( + protected async getContainerWithLeaseUpdated( account: string, container: string, context: Context, @@ -3185,7 +3201,7 @@ export default class LokiBlobMetadataStore * Get a blob document model from Loki collection. * Will throw BlobNotFound storage error if blob doesn't exist. * - * @private + * @protected * @param {string} account * @param {string} container * @param {string} blob @@ -3196,7 +3212,7 @@ export default class LokiBlobMetadataStore * @returns {Promise} * @memberof LokiBlobMetadataStore */ - private async getBlobWithLeaseUpdated( + protected async getBlobWithLeaseUpdated( account: string, container: string, blob: string, @@ -3210,7 +3226,7 @@ export default class LokiBlobMetadataStore * Get a blob document model from Loki collection. * Will NOT throw BlobNotFound storage error if blob doesn't exist. * - * @private + * @protected * @param {string} account * @param {string} container * @param {string} blob @@ -3221,7 +3237,7 @@ export default class LokiBlobMetadataStore * @returns {(Promise)} * @memberof LokiBlobMetadataStore */ - private async getBlobWithLeaseUpdated( + protected async getBlobWithLeaseUpdated( account: string, container: string, blob: string, @@ -3231,7 +3247,7 @@ export default class LokiBlobMetadataStore forceCommitted?: boolean ): Promise; - private async getBlobWithLeaseUpdated( + protected async getBlobWithLeaseUpdated( account: string, container: string, blob: string, diff --git a/src/blob/utils/constants.ts b/src/blob/utils/constants.ts index 32f6f2f13..f08059f28 100644 --- a/src/blob/utils/constants.ts +++ b/src/blob/utils/constants.ts @@ -4,9 +4,11 @@ import * as Models from "../generated/artifacts/models"; export const VERSION = "3.23.0"; export const BLOB_API_VERSION = "2022-11-02"; export const DEFAULT_BLOB_SERVER_HOST_NAME = "127.0.0.1"; // Change to 0.0.0.0 when needs external access +export const DEFAULT_DATA_LAKE_SERVER_HOST_NAME = "127.0.0.1"; // Change to 0.0.0.0 when needs external access export const DEFAULT_LIST_BLOBS_MAX_RESULTS = 5000; export const DEFAULT_LIST_CONTAINERS_MAX_RESULTS = 5000; export const DEFAULT_BLOB_LISTENING_PORT = 10000; +export const DEFAULT_DATA_LAKE_LISTENING_PORT = 10003; export const IS_PRODUCTION = process.env.NODE_ENV === "production"; export const DEFAULT_BLOB_LOKI_DB_PATH = "__azurite_db_blob__.json"; export const DEFAULT_BLOB_EXTENT_LOKI_DB_PATH = diff --git a/src/common/ConfigurationBase.ts b/src/common/ConfigurationBase.ts index 42336eec7..c4ba5cd76 100644 --- a/src/common/ConfigurationBase.ts +++ b/src/common/ConfigurationBase.ts @@ -22,6 +22,7 @@ export default abstract class ConfigurationBase { public readonly pwd: string = "", public readonly oauth?: string, public readonly disableProductStyleUrl: boolean = false, + public readonly clearDB: boolean = false, ) {} public hasCert() { diff --git a/src/common/Environment.ts b/src/common/Environment.ts index 5b90ea6b9..df464cbf9 100644 --- a/src/common/Environment.ts +++ b/src/common/Environment.ts @@ -2,7 +2,9 @@ import args from "args"; import { DEFAULT_BLOB_LISTENING_PORT, - DEFAULT_BLOB_SERVER_HOST_NAME + DEFAULT_BLOB_SERVER_HOST_NAME, + DEFAULT_DATA_LAKE_LISTENING_PORT, + DEFAULT_DATA_LAKE_SERVER_HOST_NAME } from "../blob/utils/constants"; import { @@ -28,6 +30,16 @@ args "Optional. Customize listening port for blob", DEFAULT_BLOB_LISTENING_PORT ) + .option( + ["", "datalakeHost"], + "Optional. Customize listening address for datalake", + DEFAULT_DATA_LAKE_SERVER_HOST_NAME + ) + .option( + ["", "datalakePort"], + "Optional. Customize listening port for datalake", + DEFAULT_DATA_LAKE_LISTENING_PORT + ) .option( ["", "queueHost"], "Optional. Customize listening address for queue", @@ -88,6 +100,14 @@ export default class Environment implements IEnvironment { return this.flags.blobPort; } + public datalakeHost(): string | undefined { + return this.flags.datalakeHost; + } + + public datalakePort(): number | undefined { + return this.flags.datalakePort; + } + public queueHost(): string | undefined { return this.flags.queueHost; } diff --git a/src/common/VSCEnvironment.ts b/src/common/VSCEnvironment.ts index 179c6853d..75da49d8e 100644 --- a/src/common/VSCEnvironment.ts +++ b/src/common/VSCEnvironment.ts @@ -15,6 +15,14 @@ export default class VSCEnvironment implements IEnvironment { return this.workspaceConfiguration.get("blobPort"); } + public datalakeHost(): string | undefined { + return this.workspaceConfiguration.get("datalakeHost"); + } + + public datalakePort(): number | undefined { + return this.workspaceConfiguration.get("datalakePort"); + } + public queueHost(): string | undefined { return this.workspaceConfiguration.get("queueHost"); } diff --git a/src/common/VSCServerManagerBlob.ts b/src/common/VSCServerManagerBlob.ts index 03146322e..d84137baf 100644 --- a/src/common/VSCServerManagerBlob.ts +++ b/src/common/VSCServerManagerBlob.ts @@ -4,9 +4,11 @@ import BlobConfiguration from "../blob/BlobConfiguration"; import BlobServer from "../blob/BlobServer"; import { DEFAULT_BLOB_EXTENT_LOKI_DB_PATH, + DEFAULT_BLOB_LISTENING_PORT, DEFAULT_BLOB_LOKI_DB_PATH, DEFAULT_BLOB_PERSISTENCE_ARRAY, - DEFAULT_BLOB_PERSISTENCE_PATH + DEFAULT_BLOB_PERSISTENCE_PATH, + DEFAULT_BLOB_SERVER_HOST_NAME } from "../blob/utils/constants"; import * as Logger from "./Logger"; import NoLoggerStrategy from "./NoLoggerStrategy"; @@ -72,8 +74,8 @@ export default class VSCServerManagerBlob extends VSCServerManagerBase { // Initialize server configuration const config = new BlobConfiguration( - env.blobHost(), - env.blobPort(), + env.blobHost() || DEFAULT_BLOB_SERVER_HOST_NAME, + env.blobPort() || DEFAULT_BLOB_LISTENING_PORT, join(location, DEFAULT_BLOB_LOKI_DB_PATH), join(location, DEFAULT_BLOB_EXTENT_LOKI_DB_PATH), DEFAULT_BLOB_PERSISTENCE_ARRAY, diff --git a/src/common/utils/constants.ts b/src/common/utils/constants.ts index 6bf50c37b..40beaf699 100644 --- a/src/common/utils/constants.ts +++ b/src/common/utils/constants.ts @@ -1,3 +1,5 @@ +import { Options as SequelizeOptions } from "sequelize"; + export const AZURITE_ACCOUNTS_ENV = "AZURITE_ACCOUNTS"; // Customize account name and keys by env export const DEFAULT_ACCOUNTS_REFRESH_INTERVAL = 60 * 1000; // 60s export const DEFAULT_FD_CACHE_NUMBER = 100; @@ -21,19 +23,18 @@ export const NO_ACCOUNT_HOST_NAMES = new Set().add("host.docker.internal"); // Use utf8mb4_bin instead of utf8mb4_general_ci to honor case sensitive // https://dev.mysql.com/doc/refman/8.0/en/case-sensitivity.html export const DEFAULT_SQL_COLLATE = "utf8mb4_bin"; -export const DEFAULT_SQL_OPTIONS = { +export const DEFAULT_SQL_OPTIONS: SequelizeOptions = { logging: false, pool: { - max: 20, + max: 50, min: 0, - acquire: 30000, - idle: 10000 + acquire: 100*1000, + idle: 10000, }, - charset: DEFAULT_SQL_CHARSET, - collate: DEFAULT_SQL_COLLATE, dialectOptions: { - timezone: "+00:00" - } + timezone: "+00:00", + charset: DEFAULT_SQL_CHARSET, + }, }; export const BEARER_TOKEN_PREFIX = "Bearer"; From a1ada6281118de5a758ef1dc04250d8a12b9da2a Mon Sep 17 00:00:00 2001 From: Mahmoud Bahaa Date: Fri, 21 Apr 2023 03:16:21 +0200 Subject: [PATCH 4/4] * Introduce new end point dfs and added new test cases for it * Updated visual studio extension file and added binary azurite-datalake,... * Updated readme, swagger definition changes * Updated change log * Added dfs test pipelines to azure-pipelines --- .vscode/launch.json | 71 + ChangeLog.md | 4 + README.mcr.md | 21 +- README.md | 121 +- azure-pipelines.yml | 147 + package-lock.json | 531 +- package.json | 52 +- src/azurite.ts | 36 +- src/blob/BlobServerFactory.ts | 14 +- src/common/VSCServerManagerDataLake.ts | 95 + src/common/utils/utils.ts | 8 + src/dfs/DataLakeRequestListenerFactory.ts | 251 + src/dfs/DataLakeServer.ts | 39 + src/dfs/DataLakeServerFactory.ts | 32 + src/dfs/SqlDataLakeServer.ts | 31 + .../authentication/AccountSASAuthenticator.ts | 33 + .../authentication/BlobSASAuthenticator.ts | 48 + .../BlobSharedKeyAuthenticator.ts | 4 + .../authentication/BlobTokenAuthenticator.ts | 9 + src/dfs/authentication/IAuthenticator.ts | 6 + .../OperationAccountSASPermission.ts | 200 + .../OperationBlobSASPermission.ts | 201 + .../PublicAccessAuthenticator.ts | 46 + src/dfs/context/DataLakeContext.ts | 81 + src/dfs/errors/DataLakeError.ts | 92 + src/dfs/errors/NotImplementedError.ts | 22 + src/dfs/errors/StorageErrorFactory.ts | 338 + .../errors/StrictModelNotSupportedError.ts | 15 + src/dfs/generated/ExpressMiddlewareFactory.ts | 143 + src/dfs/generated/artifacts/mappers.ts | 8729 +++++++++++++ src/dfs/generated/artifacts/models.ts | 10261 +++++++++++++++ src/dfs/generated/artifacts/operation.ts | 99 + src/dfs/generated/artifacts/parameters.ts | 2305 ++++ src/dfs/generated/artifacts/specifications.ts | 3378 +++++ .../generated/handlers/IAppendBlobHandler.ts | 20 + src/dfs/generated/handlers/IBlobHandler.ts | 38 + .../generated/handlers/IBlockBlobHandler.ts | 22 + .../generated/handlers/IContainerHandler.ts | 33 + .../handlers/IFileSystemOperationsHandler.ts | 23 + src/dfs/generated/handlers/IHandlers.ts | 21 + .../generated/handlers/IPageBlobHandler.ts | 25 + .../handlers/IPathOperationsHandler.ts | 29 + src/dfs/generated/handlers/IServiceHandler.ts | 26 + src/dfs/generated/handlers/handlerMappers.ts | 679 + .../middleware/HandlerMiddlewareFactory.ts | 90 + .../middleware/deserializer.middleware.ts | 59 + .../middleware/dispatch.middleware.ts | 191 + .../generated/middleware/error.middleware.ts | 158 + .../middleware/serializer.middleware.ts | 57 + src/dfs/handlers/BaseHandler.ts | 20 + .../handlers/FileSystemOperationsHandler.ts | 246 + src/dfs/handlers/PathOperationsHandler.ts | 1358 ++ src/dfs/handlers/ServiceHandler.ts | 61 + src/dfs/main.ts | 56 + .../AuthenticationMiddlewareFactory.ts | 56 + .../middlewares/PreflightMiddlewareFactory.ts | 458 + .../StrictModelMiddlewareFactory.ts | 72 + .../blobStorageContext.middleware.ts | 282 + src/dfs/persistence/IDataLakeMetadataStore.ts | 237 + .../persistence/LokiDataLakeMetadataStore.ts | 845 ++ .../persistence/SqlDataLakeMetadataStore.ts | 796 ++ src/dfs/storagefiledatalake/models.ts | 53 + src/dfs/storagefiledatalake/transforms.ts | 288 + src/dfs/utils/constants.ts | 208 + src/dfs/utils/operationsMapper.ts | 628 + src/dfs/utils/utils.ts | 90 + src/extension.ts | 31 +- .../blob-storage-2021-10-04-data-lake.json | 10651 ++++++++++++++++ .../data-lake-storage.json-2021-04-10.json | 4592 +++++++ swagger/dfs.md | 46 + tests/BlobTestServerFactory.ts | 21 +- tests/dfs/apis/aborter.test.ts | 116 + tests/dfs/apis/file.test.ts | 1056 ++ tests/dfs/apis/filesystem.test.ts | 1205 ++ tests/dfs/apis/filesystemclient.test.ts | 188 + tests/dfs/apis/leaseclient.test.ts | 453 + tests/dfs/apis/pathclient.test.ts | 1857 +++ tests/dfs/apis/serviceclient.test.ts | 620 + tests/dfs/apis/specialnaming.test.ts | 349 + tests/dfs/authentication.test.ts | 154 + tests/dfs/blobCorsRequest.test.ts | 878 ++ tests/dfs/bugs.test.ts | 152 + tests/dfs/https.test.ts | 54 + .../dfs/integration/filesDirMixedApis.test.ts | 271 + tests/dfs/oauth.test.ts | 891 ++ tests/dfs/sas.test.ts | 851 ++ tests/exe.test.ts | 93 +- tests/linuxbinary.test.ts | 90 +- tests/testutils.ts | 55 +- 89 files changed, 59166 insertions(+), 196 deletions(-) create mode 100644 src/common/VSCServerManagerDataLake.ts create mode 100644 src/dfs/DataLakeRequestListenerFactory.ts create mode 100644 src/dfs/DataLakeServer.ts create mode 100644 src/dfs/DataLakeServerFactory.ts create mode 100644 src/dfs/SqlDataLakeServer.ts create mode 100644 src/dfs/authentication/AccountSASAuthenticator.ts create mode 100644 src/dfs/authentication/BlobSASAuthenticator.ts create mode 100644 src/dfs/authentication/BlobSharedKeyAuthenticator.ts create mode 100644 src/dfs/authentication/BlobTokenAuthenticator.ts create mode 100644 src/dfs/authentication/IAuthenticator.ts create mode 100644 src/dfs/authentication/OperationAccountSASPermission.ts create mode 100644 src/dfs/authentication/OperationBlobSASPermission.ts create mode 100644 src/dfs/authentication/PublicAccessAuthenticator.ts create mode 100644 src/dfs/context/DataLakeContext.ts create mode 100644 src/dfs/errors/DataLakeError.ts create mode 100644 src/dfs/errors/NotImplementedError.ts create mode 100644 src/dfs/errors/StorageErrorFactory.ts create mode 100644 src/dfs/errors/StrictModelNotSupportedError.ts create mode 100644 src/dfs/generated/ExpressMiddlewareFactory.ts create mode 100644 src/dfs/generated/artifacts/mappers.ts create mode 100644 src/dfs/generated/artifacts/models.ts create mode 100644 src/dfs/generated/artifacts/operation.ts create mode 100644 src/dfs/generated/artifacts/parameters.ts create mode 100644 src/dfs/generated/artifacts/specifications.ts create mode 100644 src/dfs/generated/handlers/IAppendBlobHandler.ts create mode 100644 src/dfs/generated/handlers/IBlobHandler.ts create mode 100644 src/dfs/generated/handlers/IBlockBlobHandler.ts create mode 100644 src/dfs/generated/handlers/IContainerHandler.ts create mode 100644 src/dfs/generated/handlers/IFileSystemOperationsHandler.ts create mode 100644 src/dfs/generated/handlers/IHandlers.ts create mode 100644 src/dfs/generated/handlers/IPageBlobHandler.ts create mode 100644 src/dfs/generated/handlers/IPathOperationsHandler.ts create mode 100644 src/dfs/generated/handlers/IServiceHandler.ts create mode 100644 src/dfs/generated/handlers/handlerMappers.ts create mode 100644 src/dfs/generated/middleware/HandlerMiddlewareFactory.ts create mode 100644 src/dfs/generated/middleware/deserializer.middleware.ts create mode 100644 src/dfs/generated/middleware/dispatch.middleware.ts create mode 100644 src/dfs/generated/middleware/error.middleware.ts create mode 100644 src/dfs/generated/middleware/serializer.middleware.ts create mode 100644 src/dfs/handlers/BaseHandler.ts create mode 100644 src/dfs/handlers/FileSystemOperationsHandler.ts create mode 100644 src/dfs/handlers/PathOperationsHandler.ts create mode 100644 src/dfs/handlers/ServiceHandler.ts create mode 100644 src/dfs/main.ts create mode 100644 src/dfs/middlewares/AuthenticationMiddlewareFactory.ts create mode 100644 src/dfs/middlewares/PreflightMiddlewareFactory.ts create mode 100644 src/dfs/middlewares/StrictModelMiddlewareFactory.ts create mode 100644 src/dfs/middlewares/blobStorageContext.middleware.ts create mode 100644 src/dfs/persistence/IDataLakeMetadataStore.ts create mode 100644 src/dfs/persistence/LokiDataLakeMetadataStore.ts create mode 100644 src/dfs/persistence/SqlDataLakeMetadataStore.ts create mode 100644 src/dfs/storagefiledatalake/models.ts create mode 100644 src/dfs/storagefiledatalake/transforms.ts create mode 100644 src/dfs/utils/constants.ts create mode 100644 src/dfs/utils/operationsMapper.ts create mode 100644 src/dfs/utils/utils.ts create mode 100644 swagger/blob-storage-2021-10-04-data-lake.json create mode 100644 swagger/data-lake-storage.json-2021-04-10.json create mode 100644 swagger/dfs.md create mode 100644 tests/dfs/apis/aborter.test.ts create mode 100644 tests/dfs/apis/file.test.ts create mode 100644 tests/dfs/apis/filesystem.test.ts create mode 100644 tests/dfs/apis/filesystemclient.test.ts create mode 100644 tests/dfs/apis/leaseclient.test.ts create mode 100644 tests/dfs/apis/pathclient.test.ts create mode 100644 tests/dfs/apis/serviceclient.test.ts create mode 100644 tests/dfs/apis/specialnaming.test.ts create mode 100644 tests/dfs/authentication.test.ts create mode 100644 tests/dfs/blobCorsRequest.test.ts create mode 100644 tests/dfs/bugs.test.ts create mode 100644 tests/dfs/https.test.ts create mode 100644 tests/dfs/integration/filesDirMixedApis.test.ts create mode 100644 tests/dfs/oauth.test.ts create mode 100644 tests/dfs/sas.test.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index 4eb29e85b..4c572f45c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -96,6 +96,30 @@ }, "outputCapture": "std" }, + { + "type": "node", + "request": "launch", + "name": "Azurite Blob Service - Loki", + "cwd": "${workspaceFolder}", + "runtimeArgs": ["-r", "ts-node/register"], + "args": ["${workspaceFolder}/src/blob/main.ts", "-d", "debug.log", "--skipApiVersionCheck"], + "env": { + "AZURITE_ACCOUNTS": "" + }, + "outputCapture": "std" + }, + { + "type": "node", + "request": "launch", + "name": "Azurite DataLake Service - Loki", + "cwd": "${workspaceFolder}", + "runtimeArgs": ["-r", "ts-node/register"], + "args": ["${workspaceFolder}/src/dfs/main.ts", "-d", "debug.log", "--skipApiVersionCheck"], + "env": { + "AZURITE_ACCOUNTS": "" + }, + "outputCapture": "std" + }, { "type": "node", "request": "launch", @@ -204,6 +228,53 @@ "internalConsoleOptions": "openOnSessionStart", "outputCapture": "std" }, + { + "type": "node", + "request": "launch", + "name": "Current Mocha TS File - DataLake SQL", + "cwd": "${workspaceFolder}", + "runtimeArgs": ["-r", "ts-node/register"], + "args": [ + "${workspaceFolder}/node_modules/mocha/bin/_mocha", + "-u", + "tdd", + "--timeout", + "999999", + "--colors", + "${workspaceFolder}/${relativeFile}" + ], + "env": { + "AZURITE_ACCOUNTS": "", + "AZURITE_TEST_DB": "mysql://root:my-secret-pw@127.0.0.1:3306/azurite_blob_test", + "NODE_TLS_REJECT_UNAUTHORIZED": "0", + "IS_DATALAKE": "true", + }, + "internalConsoleOptions": "openOnSessionStart", + "outputCapture": "std" + }, + { + "type": "node", + "request": "launch", + "name": "Current Mocha TS File - PostgreSQL", + "cwd": "${workspaceFolder}", + "runtimeArgs": ["-r", "ts-node/register"], + "args": [ + "${workspaceFolder}/node_modules/mocha/bin/_mocha", + "-u", + "tdd", + "--timeout", + "999999", + "--colors", + "${workspaceFolder}/${relativeFile}" + ], + "env": { + "AZURITE_ACCOUNTS": "", + "AZURITE_TEST_DB": "postgres://postgres:postgres@127.0.0.1:5432/azurite_dfs_test", + "NODE_TLS_REJECT_UNAUTHORIZED": "0" + }, + "internalConsoleOptions": "openOnSessionStart", + "outputCapture": "std" + }, { "name": "VSC Extension", "type": "extensionHost", diff --git a/ChangeLog.md b/ChangeLog.md index 57d699d74..bc26e868a 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -10,6 +10,10 @@ Blob: - Fixed issue of: setMetadata API allows invalid metadata name with hyphen. - Support Same features in SQL Metadata Store as Loki Metadata Store (support Blob Copy & Page Blob) +DataLake: + +- Introduced dfs endpoint with the following features see readme for more details on what is supported and what is not + ## 2023.03 Version 3.23.0 General: diff --git a/README.mcr.md b/README.mcr.md index 531c4cfd1..da92a5d07 100644 --- a/README.mcr.md +++ b/README.mcr.md @@ -17,12 +17,13 @@ Azurite is an open source Azure Storage API compatible server (emulator). Based # How to Use this Image ```bash -docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 mcr.microsoft.com/azure-storage/azurite +docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 -p 10003:10003 mcr.microsoft.com/azure-storage/azurite ``` `-p 10000:10000` will expose blob service's default listening port. `-p 10001:10001` will expose queue service's default listening port. `-p 10002:10002` will expose table service's default listening port. +`-p 10003:10003` will expose datalake service's default listening port. Just run blob service: @@ -30,16 +31,22 @@ Just run blob service: docker run -p 10000:10000 mcr.microsoft.com/azure-storage/azurite azurite-blob --blobHost 0.0.0.0 ``` +Just run datalake service: + +```bash +docker run -p 10000:10000 mcr.microsoft.com/azure-storage/azurite azurite-datalake --datalakeHost 0.0.0.0 +``` + Run the image as a service (`-d` = deamon) named `azurite` and restart unless specifically stopped (this is useful when re-starting your development machine for example) ```bash -docker run --name azurite -d --restart unless-stopped -p 10000:10000 -p 10001:10001 -p 10002:10002 mcr.microsoft.com/azure-storage/azurite +docker run --name azurite -d --restart unless-stopped -p 10000:10000 -p 10001:10001 -p 10002:10002 -p 10003:10003 mcr.microsoft.com/azure-storage/azurite ``` **Run Azurite V3 docker image with customized persisted data location** ```bash -docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 -v c:/azurite:/data mcr.microsoft.com/azure-storage/azurite +docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 -p 10003:10003 -v c:/azurite:/data mcr.microsoft.com/azure-storage/azurite ``` `-v c:/azurite:/data` will use and map host path `c:/azurite` as Azurite's workspace location. @@ -47,7 +54,7 @@ docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 -v c:/azurite:/data mcr. **Customize Azurite V3 supported parameters for docker image** ```bash -docker run -p 7777:7777 -p 8888:8888 -p 9999:9999 -v c:/azurite:/workspace mcr.microsoft.com/azure-storage/azurite azurite -l /workspace -d /workspace/debug.log --blobPort 7777 --blobHost 0.0.0.0 --queuePort 8888 --queueHost 0.0.0.0 --tablePort 9999 --tableHost 0.0.0.0 --loose --skipApiVersionCheck --disableProductStyleUrl +docker run -p 7777:7777 -p 8888:8888 -p 9999:9999 -p 6666:6666 -v c:/azurite:/workspace mcr.microsoft.com/azure-storage/azurite azurite -l /workspace -d /workspace/debug.log --blobPort 7777 --blobHost 0.0.0.0 --queuePort 8888 --queueHost 0.0.0.0 --tablePort 9999 --tableHost 0.0.0.0--datalakePort 6666 --datalakeHost 0.0.0.0 --loose --skipApiVersionCheck --disableProductStyleUrl ``` Above command will try to start Azurite image with configurations: @@ -68,13 +75,17 @@ Above command will try to start Azurite image with configurations: `--tableHost 0.0.0.0` defines table service listening endpoint to accept requests from host machine. +`--datalakePort 6666` makes Azurite blob service listen to port 6666, while `-p 6666:6666` redirects requests from host machine's port 6666 to docker instance. + +`--datalakeHost 0.0.0.0` defines blob service listening endpoint to accept requests from host machine. + `--loose` enables loose mode which ignore unsupported headers and parameters. `--skipApiVersionCheck` skip the request API version check. `--disableProductStyleUrl` force parsing storage account name from request Uri path, instead of from request Uri host. -> If you use customized azurite paramters for docker image, `--blobHost 0.0.0.0`, `--queueHost 0.0.0.0` are required parameters. +> If you use customized azurite paramters for docker image, `--blobHost 0.0.0.0`, `--datalakeHost 0.0.0.0`, `--queueHost 0.0.0.0` are required parameters. > In above sample, you need to use **double first forward slash** for location and debug path parameters to avoid a [known issue](https://stackoverflow.com/questions/48427366/docker-build-command-add-c-program-files-git-to-the-path-passed-as-build-argu) for Git on Windows. diff --git a/README.md b/README.md index d44ec9ef5..809586e41 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,14 @@ Compared to V2, Azurite V3 implements a new architecture leveraging code generat - Create/List/Delete Containers - Create/Read/List/Update/Delete Block Blobs - Create/Read/List/Update/Delete Page Blobs +- DataLake storage features align with Azure Storage API version 2022-11-02 (Refer to support matrix section below) + + - SharedKey/Account SAS/Service SAS/Public Access Authentications/OAuth + - Get/Set FileSystem(Container) Properties + - Create/List/Delete FileSystems(analogous to containers) + - Create/Read/List/Update/Delete Paths(Files/Directories) + - Get/Set Paths Properties + - lease actions on Paths - Queue storage features align with Azure Storage API version 2022-11-02 (Refer to support matrix section below) - SharedKey/Account SAS/Service SAS/OAuth - Get/Set Queue Service Properties @@ -147,6 +155,12 @@ For example, to start blob service only: $ azurite-blob -l path/to/azurite/workspace ``` +start Data Lake service only: + +```bash +$ azurite-datalake -l path/to/azurite/workspace +``` + Start queue service only: ```bash @@ -179,6 +193,9 @@ Extension supports following Visual Studio Code commands: - `Azurite: Start Table Service` Start table service - `Azurite: Close Table Service` Close table service - `Azurite: Clean Table Service` Clean table service +- `Azurite: Start DataLake Service` Start DataLake service +- `Azurite: Close DataLake Service` Close DataLake service +- `Azurite: Clean DataLake Service` Clean DataLake service Following extension configurations are supported: @@ -188,6 +205,8 @@ Following extension configurations are supported: - `azurite.queuePort` Queue service listening port, by default 10001 - `azurite.tableHost` Table service listening endpoint, by default 127.0.0.1 - `azurite.tablePort` Table service listening port, by default 10002 +- `azurite.datalakeHost` DataLake service listening endpoint, by default 127.0.0.1 +- `azurite.datalakePort` DataLake service listening port, by default 10003 - `azurite.location` Workspace location folder path (can be relative or absolute). By default, in the VS Code extension, the currently opened folder is used. If launched from the command line, the current process working directory is the default. Relative paths are resolved relative to the default folder. - `azurite.silent` Silent mode to disable access log in Visual Studio channel, by default false - `azurite.debug` Output debug log into Azurite channel, by default false @@ -206,12 +225,13 @@ Following extension configurations are supported: > Note. Find more docker images tags in https://mcr.microsoft.com/v2/azure-storage/azurite/tags/list ```bash -docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 mcr.microsoft.com/azure-storage/azurite +docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 -p 10003:10003 mcr.microsoft.com/azure-storage/azurite ``` `-p 10000:10000` will expose blob service's default listening port. `-p 10001:10001` will expose queue service's default listening port. `-p 10002:10002` will expose table service's default listening port. +`-p 10003:10003` will expose datalake service's default listening port. Or just run blob service: @@ -230,7 +250,7 @@ docker run -p 10000:10000 -p 10001:10001 -v c:/azurite:/data mcr.microsoft.com/a #### Customize all Azurite V3 supported parameters for docker image ```bash -docker run -p 7777:7777 -p 8888:8888 -p 9999:9999 -v c:/azurite:/workspace mcr.microsoft.com/azure-storage/azurite azurite -l /workspace -d /workspace/debug.log --blobPort 7777 --blobHost 0.0.0.0 --queuePort 8888 --queueHost 0.0.0.0 --tablePort 9999 --tableHost 0.0.0.0 --loose --skipApiVersionCheck --disableProductStyleUrl +docker run -p 7777:7777 -p 8888:8888 -p 9999:9999 -p 6666:6666 -v c:/azurite:/workspace mcr.microsoft.com/azure-storage/azurite azurite -l /workspace -d /workspace/debug.log --blobPort 7777 --blobHost 0.0.0.0 --queuePort 8888 --queueHost 0.0.0.0 --tablePort 9999 --tableHost 0.0.0.0 --datalakePort 6666 --datalakeHost 0.0.0.0 --loose --skipApiVersionCheck --disableProductStyleUrl ``` Above command will try to start Azurite image with configurations: @@ -251,13 +271,17 @@ Above command will try to start Azurite image with configurations: `--tableHost 0.0.0.0` defines table service listening endpoint to accept requests from host machine. +`--datalakePort 6666` makes Azurite table service listen to port 6666, while `-p 6666:6666` redirects requests from host machine's port 6666 to docker instance. + +`--datalakeHost 0.0.0.0` defines table service listening endpoint to accept requests from host machine. + `--loose` enables loose mode which ignore unsupported headers and parameters. `--skipApiVersionCheck` skip the request API version check. `--disableProductStyleUrl` force parsing storage account name from request Uri path, instead of from request Uri host. -> If you use customized azurite paramters for docker image, `--blobHost 0.0.0.0`, `--queueHost 0.0.0.0` are required parameters. +> If you use customized azurite paramters for docker image, `--blobHost 0.0.0.0`, `--datalakeHost 0.0.0.0`, `--queueHost 0.0.0.0` are required parameters. > In above sample, you need to use **double first forward slash** for location and debug path parameters to avoid a [known issue](https://stackoverflow.com/questions/48427366/docker-build-command-add-c-program-files-git-to-the-path-passed-as-build-argu) for Git on Windows. @@ -280,6 +304,7 @@ services: - "10000:10000" - "10001:10001" - "10002:10002" + - "10003:10003" ``` ### NuGet @@ -303,6 +328,7 @@ You can customize the listening address per your requirements. --blobHost 127.0.0.1 --queueHost 127.0.0.1 --tableHost 127.0.0.1 +--datalakeHost 127.0.0.1 ``` #### Allow Accepting Requests from Remote (potentially unsafe) @@ -311,6 +337,7 @@ You can customize the listening address per your requirements. --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost 0.0.0.0 +--datalakeHost 0.0.0.0 ``` ### Listening Port Configuration @@ -327,6 +354,7 @@ You can customize the listening port per your requirements. --blobPort 8888 --queuePort 9999 --tablePort 11111 +--datalakePort 2222 ``` #### Let System Auto Select an Available Port @@ -335,6 +363,7 @@ You can customize the listening port per your requirements. --blobPort 0 --queuePort 0 --tablePort 0 +--datalakePort 0 ``` > Note: The port in use is displayed on Azurite startup. @@ -473,7 +502,8 @@ Azurite will refresh customized account name and key from environment variable e By default, Azurite leverages [loki](https://github.com/techfort/LokiJS) as metadata database. However, as an in-memory database, loki limits Azurite's scalability and data persistency. -Set environment variable `AZURITE_DB=dialect://[username][:password][@]host:port/database` to make Azurite blob service switch to a SQL database based metadata storage, like MySql, SqlServer & PostgreSQL. +Set environment variable `AZURITE_DB=dialect://[username][:password][@]host:port/database` to make Azurite blob service switch to a SQL database based metadata storage, like MySql, SqlServer, PostgreSQL. +Set environment variable `AZURITE_DATALAKE_DB=dialect://[username][:password][@]host:port/database` to make Azurite datalake service switch to a SQL database based metadata storage, like MySql, SqlServer, PostgreSQL. For example, connect to MySql or SqlServer by set environment variables: @@ -481,6 +511,9 @@ For example, connect to MySql or SqlServer by set environment variables: set AZURITE_DB=mysql://username:password@localhost:3306/azurite_blob set AZURITE_DB=mssql://username:password@localhost:1024/azurite_blob set AZURITE_DB=postgres://username:password@localhost:5432/azurite_blob +set AZURITE_DATALAKE_DB=mysql://username:password@localhost:3306/azurite_datalake +set AZURITE_DATALAKE_DB=mssql://username:password@localhost:1024/azurite_datalake +set AZURITE_DATALAKE_DB=postgres://username:password@localhost:5432/azurite_datalake ``` When Azurite starts with above environment variable, it connects to the configured database, and creates tables if not exist. @@ -528,7 +561,7 @@ If you start Azurite with docker, you need to map the folder contains the cert a In following example, the local folder c:/azurite contains the cert and key files, and map it to /workspace on docker. ```bash -docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 -v c:/azurite:/workspace mcr.microsoft.com/azure-storage/azurite azurite --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost 0.0.0.0 --cert /workspace/127.0.0.1.pem --key /workspace/127.0.0.1-key.pem +docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 -p 10003:10003 -v c:/azurite:/workspace mcr.microsoft.com/azure-storage/azurite azurite --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost 0.0.0.0 --datalakeHost 0.0.0.0 --cert /workspace/127.0.0.1.pem --key /workspace/127.0.0.1-key.pem ``` ##### OpenSSL @@ -708,6 +741,21 @@ var client = new QueueClient("DefaultEndpointsProtocol=https;AccountName=devstor var client = new QueueClient(new Uri("https://127.0.0.1:10001/devstoreaccount1/queue-name"), new StorageSharedKeyCredential("devstoreaccount1", "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==")); ``` +#### Azure DataLake + +You can also instantiate DataLakeFileSystemClient, DataLakeServiceClient, or DatalakeFileClient + +```csharp +// With container url and DefaultAzureCredential +var client = new DataLakeFileSystemClient(new Uri("https://127.0.0.1:10003/devstoreaccount1/filesystem-name"), new DefaultAzureCredential()); + +// With connection string +var client = new DataLakeFileSystemClient("DefaultEndpointsProtocol=https;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=https://127.0.0.1:10003/devstoreaccount1;QueueEndpoint=https://127.0.0.1:10001/devstoreaccount1;", "filesystem-name"); + +// With account name and key +var client = new DataLakeFileSystemClient(new Uri("https://127.0.0.1:10003/devstoreaccount1/filesystem-name"), new StorageSharedKeyCredential("devstoreaccount1", "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==")); +``` + ### Storage Explorer #### Storage Explorer with Azurite HTTP @@ -756,6 +804,9 @@ Following files or folders may be created when initializing Azurite in selected - `azurite_db_blob.json` Metadata file used by Azurite blob service. (No when starting Azurite against external database) - `azurite_db_blob_extent.json` Extent metadata file used by Azurite blob service. (No when starting Azurite against external database) - `blobstorage` Persisted bindary data by Azurite blob service. +- `azurite_db_datalake.json` Metadata file used by Azurite DataLake service. (No when starting Azurite against external database) +- `azurite_db_datalake_extent.json` Extent metadata file used by Azurite DataLake service. (No when starting Azurite against external database) +- `datalakestorage` Persisted bindary data by Azurite DataLake service. - `azurite_db_queue.json` Metadata file used by Azurite queue service. (No when starting Azurite against external database) - `azurite_db_queue_extent.json` Extent metadata file used by Azurite queue service. (No when starting Azurite against external database) - `queuestorage` Persisted bindary data by Azurite queue service. @@ -809,6 +860,12 @@ The service endpoints for Azurite blob service: http://127.0.0.1:10000// ``` +The service endpoints for Azurite datalake service: + +``` +http://127.0.0.1:10003// +``` + #### Production-style URL Optionally, you could modify your hosts file, to access an account with production-style URL. @@ -819,6 +876,7 @@ First, add line(s) to your hosts file, like: 127.0.0.1 account1.blob.localhost 127.0.0.1 account1.queue.localhost 127.0.0.1 account1.table.localhost +127.0.0.1 account1.dfs.localhost ``` Secondly, set environment variables to enable customized storage accounts & keys: @@ -836,6 +894,10 @@ In the connection string below, it is assumed default ports are used. ``` DefaultEndpointsProtocol=http;AccountName=account1;AccountKey=key1;BlobEndpoint=http://account1.blob.localhost:10000;QueueEndpoint=http://account1.queue.localhost:10001;TableEndpoint=http://account1.table.localhost:10002; ``` +For dfs +``` +DefaultEndpointsProtocol=http;AccountName=account1;AccountKey=key1;BlobEndpoint=http://account1.blob.localhost:10003;QueueEndpoint=http://account1.queue.localhost:10001;TableEndpoint=http://account1.table.localhost:10002; +``` > Note. Do not access default account in this way with Azure Storage Explorer. There is a bug that Storage Explorer is always adding account name in URL path, causing failures. @@ -978,6 +1040,55 @@ Detailed support matrix: - Get Page Ranges Continuation Token - Cold Tier +Latest ersion supports for **2022-11-02** API version **datalake** service. + +- Supported Vertical Features + + - CORS and Preflight + - SharedKey Authentication + - OAuth authentication + - Shared Access Signature Account Level + - Shared Access Signature Service Level (Not support response header override in service SAS) + - Container Public Access + +- Supported REST APIs + + - FileSystem: + - Create FileSystem + - Delete FileSystem + - Get FileSystem Properties + - List FileSystems + - Set FileSystem Properties + - Path: + - Create Path + - Delete Path + - Get Path Properties + - Lease Opertaions on Path + - List paths + - Read Operation + - Update Path + - Append Data + - Flush Data + - Set Path Properties + - Blob: + - see above section for details + +- Following features or REST APIs are NOT supported or limited supported in this release (will support more features per customers feedback in future releases) + + - Path: + - Update Path + - Parallel append/flush + - Set Access Control (partially supported) + - Set Access Control Recurisve ("set" only supported, "modify" and "remove" not supported) + - UnDelete Path + - expiry is partially supported + - Blob: + - see above section for details + - Other: + - content-crc64 + - cpk info + - encryption scope + Latest version supports for **2022-11-02** API version **queue** service. Detailed support matrix: diff --git a/azure-pipelines.yml b/azure-pipelines.yml index b159421dc..887885dbd 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -154,6 +154,149 @@ jobs: displayName: "npm run test:blob" env: {} + - job: dfstestubuntu20_04 + displayName: Dfs Test Linux Ubuntu 20.04 LTS + pool: + vmImage: "ubuntu-20.04" + strategy: + matrix: + node_12_x: + node_version: 12.x + node_14_x: + node_version: 14.x + steps: + - task: NodeTool@0 + inputs: + versionSpec: "$(node_version)" + displayName: "Install Node.js" + + - script: | + npm ci --legacy-peer-deps + workingDirectory: "./" + displayName: "npm ci --legacy-peer-deps" + + - script: | + npm run test:dfs + workingDirectory: "./" + displayName: "npm run test:dfs" + env: {} + + - job: dfstestubuntu22_04 + displayName: Dfs Test Linux Ubuntu 22.04 + pool: + vmImage: "ubuntu-latest" + strategy: + matrix: + node_16_x: + node_version: 16.x + node_18_x: + node_version: 18.x + steps: + - task: NodeTool@0 + inputs: + versionSpec: "$(node_version)" + displayName: "Install Node.js" + + - script: | + npm ci --legacy-peer-deps + workingDirectory: "./" + displayName: "npm ci --legacy-peer-deps" + + - script: | + npm run test:dfs + workingDirectory: "./" + displayName: "npm run test:dfs" + env: {} + + - job: dfstestwin + displayName: Dfs Test Windows + pool: + vmImage: "windows-latest" + strategy: + matrix: + node_14_x: + node_version: 14.x + node_16_x: + node_version: 16.x + steps: + - task: NodeTool@0 + inputs: + versionSpec: "$(node_version)" + displayName: "Install Node.js" + + - script: | + npm ci --legacy-peer-deps + workingDirectory: "./" + displayName: "npm ci --legacy-peer-deps" + + - script: | + npm run test:dfs + workingDirectory: "./" + displayName: "npm run test:dfs" + env: {} + + - job: dfstestmac + displayName: Dfs Test Mac + pool: + vmImage: "macOS-latest" + strategy: + matrix: + node_14_x: + node_version: 14.x + node_16_x: + node_version: 16.x + steps: + - task: NodeTool@0 + inputs: + versionSpec: "$(node_version)" + displayName: "Install Node.js" + + - script: | + npm ci --legacy-peer-deps + workingDirectory: "./" + displayName: "npm ci --legacy-peer-deps" + + - script: | + npm run test:dfs + workingDirectory: "./" + displayName: "npm run test:dfs" + env: {} + + - job: dfstestmysql + displayName: Dfs Test Mysql + pool: + vmImage: "ubuntu-latest" + strategy: + matrix: + node_14_x: + node_version: 14.x + node_16_x: + node_version: 16.x + steps: + - task: NodeTool@0 + inputs: + versionSpec: "$(node_version)" + displayName: "Install Node.js" + + - script: | + npm ci --legacy-peer-deps + workingDirectory: "./" + displayName: "npm ci --legacy-peer-deps" + + - script: | + docker run --name mysql -p 13306:3306 -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql + sleep 60 + docker exec mysql mysql -u root -pmy-secret-pw -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION; FLUSH PRIVILEGES;" + docker exec mysql mysql -u root -pmy-secret-pw -e "create database azurite_blob_test;" + workingDirectory: "./" + displayName: "Setup mysql docker instance" + + - script: | + npm run test:dfs:sql:ci + workingDirectory: "./" + displayName: "npm run test:dfs:sql:ci" + env: {} + - job: queuetestlinux displayName: Queue Test Linux pool: @@ -366,6 +509,7 @@ jobs: azurite-blob -v azurite-queue -v azurite-table -v + azurite-datalake -v workingDirectory: "./" displayName: "Validate npm global installation from GitHub code base" @@ -414,6 +558,7 @@ jobs: azurite-blob -v azurite-queue -v azurite-table -v + azurite-datalake -v workingDirectory: "./" displayName: "Validate npm global installation from GitHub code base" @@ -462,6 +607,7 @@ jobs: azurite-blob -v azurite-queue -v azurite-table -v + azurite-datalake -v workingDirectory: "./" displayName: "Validate npm global installation from GitHub code base" @@ -485,6 +631,7 @@ jobs: docker run xstoreazurite.azurecr.io/public/azure-storage/azurite:latest azurite-blob -v docker run xstoreazurite.azurecr.io/public/azure-storage/azurite:latest azurite-queue -v docker run xstoreazurite.azurecr.io/public/azure-storage/azurite:latest azurite-table -v + docker run xstoreazurite.azurecr.io/public/azure-storage/azurite:latest azurite-datalake -v workingDirectory: "./" displayName: "Validate docker image" diff --git a/package-lock.json b/package-lock.json index 9b74c3d4a..d70518fef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "morgan": "^1.9.1", "multistream": "^2.1.1", "mysql2": "^3.2.0", + "pg": "^8.10.0", "rimraf": "^3.0.2", "sequelize": "^6.3.0", "stoppable": "^1.1.0", @@ -35,6 +36,7 @@ "bin": { "azurite": "dist/src/azurite.js", "azurite-blob": "dist/src/blob/main.js", + "azurite-datalake": "dist/src/dfs/main.js", "azurite-queue": "dist/src/queue/main.js", "azurite-table": "dist/src/table/main.js" }, @@ -43,6 +45,7 @@ "@azure/core-rest-pipeline": "^1.2.0", "@azure/data-tables": "^13.0.1", "@azure/storage-blob": "^12.9.0", + "@azure/storage-file-datalake": "^12.12.0", "@azure/storage-queue": "^12.8.0", "@types/args": "^5.0.0", "@types/async": "^3.0.1", @@ -728,6 +731,86 @@ "node": ">=4.0.0" } }, + "node_modules/@azure/storage-file-datalake": { + "version": "12.12.0", + "resolved": "https://registry.npmjs.org/@azure/storage-file-datalake/-/storage-file-datalake-12.12.0.tgz", + "integrity": "sha512-S/vJaV4LZUnVFFlL8PWfSNug1UoAnU2aC+Dp4YvfZjg1iSinfnPP0gvmTi4PZHZ8QdO/fMjWLPBj6zhqbALDtQ==", + "dev": true, + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-http": "^3.0.0", + "@azure/core-paging": "^1.1.1", + "@azure/core-tracing": "1.0.0-preview.13", + "@azure/logger": "^1.0.0", + "@azure/storage-blob": "^12.13.0", + "events": "^3.0.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@azure/storage-file-datalake/node_modules/@azure/core-http": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@azure/core-http/-/core-http-3.0.0.tgz", + "integrity": "sha512-BxI2SlGFPPz6J1XyZNIVUf0QZLBKFX+ViFjKOkzqD18J1zOINIQ8JSBKKr+i+v8+MB6LacL6Nn/sP/TE13+s2Q==", + "dev": true, + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.3.0", + "@azure/core-tracing": "1.0.0-preview.13", + "@azure/core-util": "^1.1.1", + "@azure/logger": "^1.0.0", + "@types/node-fetch": "^2.5.0", + "@types/tunnel": "^0.0.3", + "form-data": "^4.0.0", + "node-fetch": "^2.6.7", + "process": "^0.11.10", + "tslib": "^2.2.0", + "tunnel": "^0.0.6", + "uuid": "^8.3.0", + "xml2js": "^0.4.19" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@azure/storage-file-datalake/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@azure/storage-file-datalake/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@azure/storage-file-datalake/node_modules/xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/@azure/storage-queue": { "version": "12.13.0", "resolved": "https://registry.npmjs.org/@azure/storage-queue/-/storage-queue-12.13.0.tgz", @@ -1820,23 +1903,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.58.0.tgz", - "integrity": "sha512-b+w8ypN5CFvrXWQb9Ow9T4/6LC2MikNf1viLkYTiTbkQl46CnR69w7lajz1icW0TBsYmlpg+mRzFJ4LEJ8X9NA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.58.0", - "@typescript-eslint/visitor-keys": "5.58.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@typescript-eslint/type-utils": { "version": "5.59.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.0.tgz", @@ -1944,69 +2010,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/@typescript-eslint/types": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.58.0.tgz", - "integrity": "sha512-JYV4eITHPzVQMnHZcYJXl2ZloC7thuUHrcUmxtzvItyKPvQ50kb9QXBkgNAt90OYMqwaodQh2kHutWZl1fc+1g==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.58.0.tgz", - "integrity": "sha512-cRACvGTodA+UxnYM2uwA2KCwRL7VAzo45syNysqlMyNyjw0Z35Icc9ihPJZjIYuA5bXJYiJ2YGUB59BqlOZT1Q==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.58.0", - "@typescript-eslint/visitor-keys": "5.58.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@typescript-eslint/utils": { "version": "5.59.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.0.tgz", @@ -2130,23 +2133,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.58.0.tgz", - "integrity": "sha512-/fBraTlPj0jwdyTwLyrRTxv/3lnU2H96pNTVM6z3esTWLtA5MZ9ghSMJ7Rb+TtUAdtEw9EyJzJ0EydIMKxQ9gA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.58.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -3595,6 +3581,14 @@ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" }, + "node_modules/buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", + "engines": { + "node": ">=4" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -7878,6 +7872,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -7974,11 +7973,80 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, + "node_modules/pg": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.10.0.tgz", + "integrity": "sha512-ke7o7qSTMb47iwzOSaZMfeR7xToFdkE71ifIipOAAaLIM0DYzfOAXlgFFmYUIE2BcJtvnVlGCID84ZzCegE8CQ==", + "dependencies": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.5.0", + "pg-pool": "^3.6.0", + "pg-protocol": "^1.6.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, "node_modules/pg-connection-string": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.0.tgz", + "integrity": "sha512-clFRf2ksqd+F497kWFyM21tMjeikn60oGDmqMT8UBrynEwVEX/5R5xd2sdvdo1cZCFlguORNpVuqxIj+aK4cfQ==", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", + "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dependencies": { + "split2": "^4.1.0" + } + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -8375,6 +8443,41 @@ "node": ">= 10.0.0" } }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/prebuild-install": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", @@ -9230,6 +9333,14 @@ "source-map": "^0.5.6" } }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/sqlstring": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.2.tgz", @@ -10210,6 +10321,14 @@ "node": ">=4.0" } }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, "node_modules/yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", @@ -10799,6 +10918,73 @@ } } }, + "@azure/storage-file-datalake": { + "version": "12.12.0", + "resolved": "https://registry.npmjs.org/@azure/storage-file-datalake/-/storage-file-datalake-12.12.0.tgz", + "integrity": "sha512-S/vJaV4LZUnVFFlL8PWfSNug1UoAnU2aC+Dp4YvfZjg1iSinfnPP0gvmTi4PZHZ8QdO/fMjWLPBj6zhqbALDtQ==", + "dev": true, + "requires": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-http": "^3.0.0", + "@azure/core-paging": "^1.1.1", + "@azure/core-tracing": "1.0.0-preview.13", + "@azure/logger": "^1.0.0", + "@azure/storage-blob": "^12.13.0", + "events": "^3.0.0", + "tslib": "^2.2.0" + }, + "dependencies": { + "@azure/core-http": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@azure/core-http/-/core-http-3.0.0.tgz", + "integrity": "sha512-BxI2SlGFPPz6J1XyZNIVUf0QZLBKFX+ViFjKOkzqD18J1zOINIQ8JSBKKr+i+v8+MB6LacL6Nn/sP/TE13+s2Q==", + "dev": true, + "requires": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.3.0", + "@azure/core-tracing": "1.0.0-preview.13", + "@azure/core-util": "^1.1.1", + "@azure/logger": "^1.0.0", + "@types/node-fetch": "^2.5.0", + "@types/tunnel": "^0.0.3", + "form-data": "^4.0.0", + "node-fetch": "^2.6.7", + "process": "^0.11.10", + "tslib": "^2.2.0", + "tunnel": "^0.0.6", + "uuid": "^8.3.0", + "xml2js": "^0.4.19" + } + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, + "xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + } + } + }, "@azure/storage-queue": { "version": "12.13.0", "resolved": "https://registry.npmjs.org/@azure/storage-queue/-/storage-queue-12.13.0.tgz", @@ -11637,16 +11823,6 @@ } } }, - "@typescript-eslint/scope-manager": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.58.0.tgz", - "integrity": "sha512-b+w8ypN5CFvrXWQb9Ow9T4/6LC2MikNf1viLkYTiTbkQl46CnR69w7lajz1icW0TBsYmlpg+mRzFJ4LEJ8X9NA==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.58.0", - "@typescript-eslint/visitor-keys": "5.58.0" - } - }, "@typescript-eslint/type-utils": { "version": "5.59.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.0.tgz", @@ -11707,44 +11883,6 @@ } } }, - "@typescript-eslint/types": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.58.0.tgz", - "integrity": "sha512-JYV4eITHPzVQMnHZcYJXl2ZloC7thuUHrcUmxtzvItyKPvQ50kb9QXBkgNAt90OYMqwaodQh2kHutWZl1fc+1g==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.58.0.tgz", - "integrity": "sha512-cRACvGTodA+UxnYM2uwA2KCwRL7VAzo45syNysqlMyNyjw0Z35Icc9ihPJZjIYuA5bXJYiJ2YGUB59BqlOZT1Q==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.58.0", - "@typescript-eslint/visitor-keys": "5.58.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, "@typescript-eslint/utils": { "version": "5.59.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.0.tgz", @@ -11819,16 +11957,6 @@ } } }, - "@typescript-eslint/visitor-keys": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.58.0.tgz", - "integrity": "sha512-/fBraTlPj0jwdyTwLyrRTxv/3lnU2H96pNTVM6z3esTWLtA5MZ9ghSMJ7Rb+TtUAdtEw9EyJzJ0EydIMKxQ9gA==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.58.0", - "eslint-visitor-keys": "^3.3.0" - } - }, "accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -13141,6 +13269,11 @@ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" }, + "buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" + }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -16307,6 +16440,11 @@ "aggregate-error": "^3.0.0" } }, + "packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -16387,11 +16525,61 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, + "pg": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.10.0.tgz", + "integrity": "sha512-ke7o7qSTMb47iwzOSaZMfeR7xToFdkE71ifIipOAAaLIM0DYzfOAXlgFFmYUIE2BcJtvnVlGCID84ZzCegE8CQ==", + "requires": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.5.0", + "pg-pool": "^3.6.0", + "pg-protocol": "^1.6.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + } + }, "pg-connection-string": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" }, + "pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" + }, + "pg-pool": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.0.tgz", + "integrity": "sha512-clFRf2ksqd+F497kWFyM21tMjeikn60oGDmqMT8UBrynEwVEX/5R5xd2sdvdo1cZCFlguORNpVuqxIj+aK4cfQ==", + "requires": {} + }, + "pg-protocol": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", + "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" + }, + "pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "requires": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + } + }, + "pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "requires": { + "split2": "^4.1.0" + } + }, "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -16671,6 +16859,29 @@ } } }, + "postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" + }, + "postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==" + }, + "postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" + }, + "postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "requires": { + "xtend": "^4.0.0" + } + }, "prebuild-install": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", @@ -17283,6 +17494,11 @@ "source-map": "^0.5.6" } }, + "split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==" + }, "sqlstring": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.2.tgz", @@ -18037,6 +18253,11 @@ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", diff --git a/package.json b/package.json index 0947eca7d..de75199ca 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "bin": { "azurite": "./dist/src/azurite.js", "azurite-blob": "./dist/src/blob/main.js", + "azurite-datalake": "dist/src/dfs/main.js", "azurite-queue": "./dist/src/queue/main.js", "azurite-table": "./dist/src/table/main.js" }, @@ -32,6 +33,7 @@ "morgan": "^1.9.1", "multistream": "^2.1.1", "mysql2": "^3.2.0", + "pg": "^8.10.0", "rimraf": "^3.0.2", "sequelize": "^6.3.0", "stoppable": "^1.1.0", @@ -48,6 +50,7 @@ "@azure/core-rest-pipeline": "^1.2.0", "@azure/data-tables": "^13.0.1", "@azure/storage-blob": "^12.9.0", + "@azure/storage-file-datalake": "^12.12.0", "@azure/storage-queue": "^12.8.0", "@types/args": "^5.0.0", "@types/async": "^3.0.1", @@ -96,6 +99,9 @@ "onCommand:azurite.start_blob", "onCommand:azurite.close_blob", "onCommand:azurite.clean_blob", + "onCommand:azurite.start_datalake", + "onCommand:azurite.close_datalake", + "onCommand:azurite.clean_datalake", "onCommand:azurite.start_queue", "onCommand:azurite.close_queue", "onCommand:azurite.clean_queue", @@ -135,6 +141,21 @@ "title": "Clean Blob Service", "category": "Azurite" }, + { + "command": "azurite.start_datalake", + "title": "Start DataLake Service", + "category": "Azurite" + }, + { + "command": "azurite.close_datalake", + "title": "Close DataLake Service", + "category": "Azurite" + }, + { + "command": "azurite.clean_datalake", + "title": "Clean Blob Service", + "category": "Azurite" + }, { "command": "azurite.start_queue", "title": "Start Queue Service", @@ -219,6 +240,16 @@ "default": 10000, "description": "Blob service listening port, by default 10000" }, + "azurite.datalakeHost": { + "type": "string", + "default": "127.0.0.1", + "description": "DataLake service listening endpoint, by default 127.0.0.1" + }, + "azurite.datalakePort": { + "type": "number", + "default": 10003, + "description": "DataLake service listening port, by default 10003" + }, "azurite.queueHost": { "type": "string", "default": "127.0.0.1", @@ -273,19 +304,24 @@ "docker:publish-manifest-latest": "cross-var docker manifest push xstoreazurite.azurecr.io/public/azure-storage/azurite:latest", "prepare": "npm run build", "build": "tsc", - "build:autorest:debug": "autorest ./swagger/blob.md --typescript --typescript.debugger --use=S:/GitHub/XiaoningLiu/autorest.typescript.server", - "build:autorest:blob": "autorest ./swagger/blob.md --typescript --use=S:/GitHub/XiaoningLiu/autorest.typescript.server", - "build:autorest:queue": "autorest ./swagger/queue.md --typescript --use=S:/GitHub/XiaoningLiu/autorest.typescript.server", - "build:autorest:table": "autorest ./swagger/table.md --typescript --use=S:/GitHub/XiaoningLiu/autorest.typescript.server", + "build:autorest:debug": "autorest ./swagger/blob.md --typescript --typescript.debugger --use=../autorest.typescript.server", + "build:autorest:blob": "autorest ./swagger/blob.md --typescript --use=../autorest.typescript.server", + "build:autorest:dfs": "autorest ./swagger/dfs.md --typescript --use=../autorest.typescript.server", + "build:autorest:queue": "autorest ./swagger/queue.md --typescript --use=../autorest.typescript.server", + "build:autorest:table": "autorest ./swagger/table.md --typescript --use=../autorest.typescript.server", "build:exe": "node ./scripts/buildExe.js", "build:linux": "node ./scripts/buildLinux.js", "watch": "tsc -watch -p ./", "blob": "node -r ts-node/register src/blob/main.ts", "queue": "node -r ts-node/register src/queue/main.ts", "table": "node -r ts-node/register src/table/main.ts", + "dfs": "node -r ts-node/register src/dfs/main.ts", "azurite": "node -r ts-node/register src/azurite.ts", "lint": "npx eslint src/**/*.ts", - "test": "npm run lint && cross-env NODE_TLS_REJECT_UNAUTHORIZED=0 mocha --compilers ts-node/register --no-timeouts --grep @loki --recursive --exit tests/**/*.test.ts tests/**/**/*.test.ts", + "test": "npm run lint && cross-env NODE_TLS_REJECT_UNAUTHORIZED=0 mocha --compilers ts-node/register --no-timeouts --recursive --exit tests/**/*.test.ts tests/**/**/*.test.ts tests/**/**/**/*.test.ts", + "test:dfs": "npm run lint && cross-env NODE_TLS_REJECT_UNAUTHORIZED=0 IS_DATALAKE=true mocha --compilers ts-node/register --no-timeouts --grep @loki --recursive --exit tests/blob/*.test.ts tests/blob/**/*.test.ts tests/dfs/*.test.ts tests/dfs/**/*.test.ts tests/dfs/**/**/*.test.ts", + "test:dfs:sql": "npm run lint && cross-env cross-env NODE_TLS_REJECT_UNAUTHORIZED=0 IS_DATALAKE=true AZURITE_TEST_DB=mysql://root:my-secret-pw@127.0.0.1:3306/azurite_blob_test mocha --compilers ts-node/register --no-timeouts --grep @sql --recursive --exit tests/blob/*.test.ts tests/blob/**/*.test.ts tests/dfs/*.test.ts tests/dfs/**/*.test.ts", + "test:dfs:sql:ci": "npm run lint && cross-env cross-env NODE_TLS_REJECT_UNAUTHORIZED=0 IS_DATALAKE=true AZURITE_TEST_DB=mysql://root:my-secret-pw@127.0.0.1:13306/azurite_blob_test mocha --compilers ts-node/register --no-timeouts --grep @sql --recursive --exit tests/blob/*.test.ts tests/blob/**/*.test.ts tests/dfs/*.test.ts tests/dfs/**/*.test.ts", "test:blob": "npm run lint && cross-env NODE_TLS_REJECT_UNAUTHORIZED=0 mocha --compilers ts-node/register --no-timeouts --grep @loki --recursive --exit tests/blob/*.test.ts tests/blob/**/*.test.ts", "test:blob:sql": "npm run lint && cross-env cross-env NODE_TLS_REJECT_UNAUTHORIZED=0 AZURITE_TEST_DB=mysql://root:my-secret-pw@127.0.0.1:3306/azurite_blob_test mocha --compilers ts-node/register --no-timeouts --grep @sql --recursive --exit tests/blob/*.test.ts tests/blob/**/*.test.ts", "test:blob:sql:ci": "npm run lint && cross-env cross-env NODE_TLS_REJECT_UNAUTHORIZED=0 AZURITE_TEST_DB=mysql://root:my-secret-pw@127.0.0.1:13306/azurite_blob_test mocha --compilers ts-node/register --no-timeouts --grep @sql --recursive --exit tests/blob/*.test.ts tests/blob/**/*.test.ts", @@ -295,8 +331,8 @@ "test:linux": "npm run lint && cross-env NODE_TLS_REJECT_UNAUTHORIZED=0 mocha --compilers ts-node/register --no-timeouts tests/linuxbinary.test.ts --exit", "clean": "rimraf dist typings *.log coverage __testspersistence__ temp __testsstorage__ .nyc_output debug.log *.vsix *.tgz", "clean:deep": "npm run clean && rimraf debug.log __*", - "validate:npmpack:win": "npm install --legacy-peer-deps && npm run build && npm pack && cross-var npm install -g azurite-$npm_package_version.tgz && azurite -v && azurite-blob -v && azurite-queue -v && azurite-table -v", - "validate:npmpack:linux_mac": "npm install --legacy-peer-deps && npm run build && npm pack && cross-var sudo npm install -g azurite-$npm_package_version.tgz && azurite -v && azurite-blob -v && azurite-queue -v && azurite-table -v", + "validate:npmpack:win": "npm install --legacy-peer-deps && npm run build && npm pack && cross-var npm install -g azurite-$npm_package_version.tgz && azurite -v && azurite-blob -v && azurite-queue -v && azurite-table -v && azurite-datalake -v", + "validate:npmpack:linux_mac": "npm install --legacy-peer-deps && npm run build && npm pack && cross-var sudo npm install -g azurite-$npm_package_version.tgz && azurite -v && azurite-blob -v && azurite-queue -v && azurite-table -v && azurite-datalake -v", "db:migrate:blob:metadata": "sequelize db:migrate --config migrations/blob/metadata/config/config.json --migrations-path migrations/blob/metadata/migrations", "db:create:blob:metadata": "sequelize db:create --config migrations/blob/metadata/config/config.json --migrations-path migrations/blob/metadata/migrations" }, @@ -320,4 +356,4 @@ "url": "https://github.com/azure/azurite/issues" }, "homepage": "https://github.com/azure/azurite#readme" -} \ No newline at end of file +} diff --git a/src/azurite.ts b/src/azurite.ts index 5801d5481..c1aea6e99 100644 --- a/src/azurite.ts +++ b/src/azurite.ts @@ -23,16 +23,22 @@ import TableConfiguration from "./table/TableConfiguration"; import TableServer from "./table/TableServer"; import { DEFAULT_TABLE_LOKI_DB_PATH } from "./table/utils/constants"; +import { DataLakeServerFactory } from "./dfs/DataLakeServerFactory"; +import DataLakeServer from "./dfs/DataLakeServer"; +import SqlDataLakeServer from "./dfs/SqlDataLakeServer"; // tslint:disable:no-console function shutdown( blobServer: BlobServer | SqlBlobServer, queueServer: QueueServer, - tableServer: TableServer + tableServer: TableServer, + dfsServer: DataLakeServer | SqlDataLakeServer ) { const blobBeforeCloseMessage = `Azurite Blob service is closing...`; const blobAfterCloseMessage = `Azurite Blob service successfully closed`; + const dfsBeforeCloseMessage = `Azurite DataLake service is closing...`; + const dfsAfterCloseMessage = `Azurite DataLake service successfully closed`; const queueBeforeCloseMessage = `Azurite Queue service is closing...`; const queueAfterCloseMessage = `Azurite Queue service successfully closed`; const tableBeforeCloseMessage = `Azurite Table service is closing...`; @@ -52,6 +58,11 @@ function shutdown( tableServer.close().then(() => { console.log(tableAfterCloseMessage); }); + + console.log(dfsBeforeCloseMessage); + dfsServer.close().then(() => { + console.log(dfsAfterCloseMessage); + }); } /** @@ -75,6 +86,10 @@ async function main() { const blobServer = await blobServerFactory.createServer(env); const blobConfig = blobServer.config; + const dfsServerFactory = new DataLakeServerFactory(); + const dfsServer = await dfsServerFactory.createServer(env); + const dfsConfig = dfsServer.config; + // TODO: Align with blob DEFAULT_BLOB_PERSISTENCE_ARRAY // TODO: Join for all paths in the array DEFAULT_QUEUE_PERSISTENCE_ARRAY[0].locationPath = join( @@ -157,15 +172,28 @@ async function main() { `Azurite Table service is successfully listening at ${tableServer.getHttpServerAddress()}` ); + // Start server + console.log( + `Azurite DataLake service is starting at ${dfsConfig.getHttpServerAddress()}` + ); + await dfsServer.start(); + console.log( + `Azurite DataLake service is successfully listening at ${dfsConfig.getHttpServerAddress()}` + ); + // Handle close event process .once("message", (msg) => { if (msg === "shutdown") { - shutdown(blobServer, queueServer, tableServer); + shutdown(blobServer, queueServer, tableServer, dfsServer); } }) - .once("SIGINT", () => shutdown(blobServer, queueServer, tableServer)) - .once("SIGTERM", () => shutdown(blobServer, queueServer, tableServer)); + .once("SIGINT", () => + shutdown(blobServer, queueServer, tableServer, dfsServer) + ) + .once("SIGTERM", () => + shutdown(blobServer, queueServer, tableServer, dfsServer) + ); } main().catch((err) => { diff --git a/src/blob/BlobServerFactory.ts b/src/blob/BlobServerFactory.ts index 7a08b542a..d05c60771 100644 --- a/src/blob/BlobServerFactory.ts +++ b/src/blob/BlobServerFactory.ts @@ -29,7 +29,9 @@ export class BlobServerFactory { DEFAULT_BLOB_LOKI_DB_PATH, DEFAULT_BLOB_EXTENT_LOKI_DB_PATH, SqlBlobServer, - BlobServer + BlobServer, + "blobHost", + "blobPort" ); } @@ -44,6 +46,8 @@ export class BlobServerFactory { defaultExtentLokiDBPath: string, sqlSeverClass: any, blobServerClass: any, + hostProperty: string, + portProerty: string, ): Promise { // TODO: Check it's in Visual Studio Code environment or not const isVSC = false; @@ -70,8 +74,8 @@ export class BlobServerFactory { if (isSQL) { const config = new SqlBlobConfiguration( - env.blobHost() || defaultHost, - env.blobPort() || defaultPort, + (env as any)[hostProperty]() || defaultHost, + (env as any)[portProerty]() || defaultPort, databaseConnectionString!, DEFAULT_SQL_OPTIONS, persistenceArray, @@ -91,8 +95,8 @@ export class BlobServerFactory { return new sqlSeverClass(config); } else { const config = new BlobConfiguration( - env.blobHost() || defaultHost, - env.blobPort() || defaultPort, + (env as any)[hostProperty]() || defaultHost, + (env as any)[portProerty]() || defaultPort, join(location, defaultLokiDBPath), join(location, defaultExtentLokiDBPath), persistenceArray, diff --git a/src/common/VSCServerManagerDataLake.ts b/src/common/VSCServerManagerDataLake.ts new file mode 100644 index 000000000..4a2a35827 --- /dev/null +++ b/src/common/VSCServerManagerDataLake.ts @@ -0,0 +1,95 @@ +import { join } from "path"; + +import DataLakeServer from "../dfs/DataLakeServer"; +import { + DEFAULT_BLOB_EXTENT_LOKI_DB_PATH, + DEFAULT_BLOB_LOKI_DB_PATH, + DEFAULT_BLOB_PERSISTENCE_ARRAY, + DEFAULT_BLOB_PERSISTENCE_PATH +} from "../blob/utils/constants"; +import * as Logger from "./Logger"; +import NoLoggerStrategy from "./NoLoggerStrategy"; +import VSCChannelLoggerStrategy from "./VSCChannelLoggerStrategy"; +import VSCChannelWriteStream from "./VSCChannelWriteStream"; +import VSCEnvironment from "./VSCEnvironment"; +import VSCServerManagerBase from "./VSCServerManagerBase"; +import VSCServerManagerClosedState from "./VSCServerManagerClosedState"; +import BlobConfiguration from "../blob/BlobConfiguration"; +import { DEFAULT_DATA_LAKE_LISTENING_PORT, DEFAULT_DATA_LAKE_SERVER_HOST_NAME } from "../dfs/utils/constants"; + +export default class VSCServerManagerDataLake extends VSCServerManagerBase { + public readonly accessChannelStream = new VSCChannelWriteStream( + "Azurite DataLake" + ); + private debuggerLoggerStrategy = new VSCChannelLoggerStrategy( + "Azurite DataLake Debug" + ); + + public constructor() { + super("Azurite DataLake Service", new VSCServerManagerClosedState()); + } + + public getStartCommand(): string { + return "azurite.start_datalake"; + } + + public getCloseCommand(): string { + return "azurite.close_datalake"; + } + + public getCleanCommand(): string { + return "azurite.clean_datalake"; + } + + public async createImpl(): Promise { + const config = await this.getConfiguration(); + Logger.default.strategy = config.enableDebugLog + ? this.debuggerLoggerStrategy + : new NoLoggerStrategy(); + this.server = new DataLakeServer(config); + } + + public async startImpl(): Promise { + await this.server!.start(); + } + + public async closeImpl(): Promise { + this.server!.close(); + } + + public async cleanImpl(): Promise { + await this.createImpl(); + await this.server!.clean(); + } + + private async getConfiguration(): Promise { + const env = new VSCEnvironment(); + const location = await env.location(); + + DEFAULT_BLOB_PERSISTENCE_ARRAY[0].locationPath = join( + location, + DEFAULT_BLOB_PERSISTENCE_PATH + ); + + // Initialize server configuration + const config = new BlobConfiguration( + env.datalakeHost() || DEFAULT_DATA_LAKE_SERVER_HOST_NAME, + env.datalakePort() || DEFAULT_DATA_LAKE_LISTENING_PORT, + join(location, DEFAULT_BLOB_LOKI_DB_PATH), + join(location, DEFAULT_BLOB_EXTENT_LOKI_DB_PATH), + DEFAULT_BLOB_PERSISTENCE_ARRAY, + !env.silent(), + this.accessChannelStream, + (await env.debug()) === true, + undefined, + env.loose(), + env.skipApiVersionCheck(), + env.cert(), + env.key(), + env.pwd(), + env.oauth(), + env.disableProductStyleUrl() + ); + return config; + } +} diff --git a/src/common/utils/utils.ts b/src/common/utils/utils.ts index 12f47291a..3706dd0ba 100644 --- a/src/common/utils/utils.ts +++ b/src/common/utils/utils.ts @@ -164,3 +164,11 @@ export async function getMD5FromStream( }); }); } + +export function getUniqueName(prefix: string): string { + return `${prefix}${new Date().getTime()}${ + Math.floor(Math.random() * 10000).toString().padStart( + 5, + "00000" + )}`; +} \ No newline at end of file diff --git a/src/dfs/DataLakeRequestListenerFactory.ts b/src/dfs/DataLakeRequestListenerFactory.ts new file mode 100644 index 000000000..f6250f95b --- /dev/null +++ b/src/dfs/DataLakeRequestListenerFactory.ts @@ -0,0 +1,251 @@ +import express from "express"; + +import PageBlobRangesManager from "../blob/handlers/PageBlobRangesManager"; +import { DEFAULT_CONTEXT_PATH } from "../blob/utils/constants"; +import IAccountDataStore from "../common/IAccountDataStore"; +import IRequestListenerFactory from "../common/IRequestListenerFactory"; +import logger from "../common/Logger"; +import { OAuthLevel } from "../common/models"; +import IExtentStore from "../common/persistence/IExtentStore"; +import { RequestListener } from "../common/ServerBase"; +import AccountSASAuthenticator from "./authentication/AccountSASAuthenticator"; +import BlobSASAuthenticator from "./authentication/BlobSASAuthenticator"; +import BlobSharedKeyAuthenticator from "./authentication/BlobSharedKeyAuthenticator"; +import BlobTokenAuthenticator from "./authentication/BlobTokenAuthenticator"; +import IAuthenticator from "./authentication/IAuthenticator"; +import PublicAccessAuthenticator from "./authentication/PublicAccessAuthenticator"; +import ExpressMiddlewareFactory from "./generated/ExpressMiddlewareFactory"; +import IHandlers from "./generated/handlers/IHandlers"; +import FileSystemOperationsHandler from "./handlers/FileSystemOperationsHandler"; +import PathOperationsHandler from "./handlers/PathOperationsHandler"; +import ServiceHandler from "./handlers/ServiceHandler"; +import AuthenticationMiddlewareFactory from "./middlewares/AuthenticationMiddlewareFactory"; +import createStorageBlobContextMiddleware from "./middlewares/blobStorageContext.middleware"; +import PreflightMiddlewareFactory from "./middlewares/PreflightMiddlewareFactory"; +import StrictModelMiddlewareFactory, { + UnsupportedHeadersBlocker, + UnsupportedParametersBlocker +} from "./middlewares/StrictModelMiddlewareFactory"; +import IDataLakeMetaDataStore from "./persistence/IDataLakeMetadataStore"; + +import morgan = require("morgan"); +import MiddlewareFactory from "../blob/generated/MiddlewareFactory"; +import AppendBlobHandler from "../blob/handlers/AppendBlobHandler"; +import BlobHandler from "../blob/handlers/BlobHandler"; +import BlockBlobHandler from "../blob/handlers/BlockBlobHandler"; +import ContainerHandler from "../blob/handlers/ContainerHandler"; +import PageBlobHandler from "../blob/handlers/PageBlobHandler"; +/** + * Default RequestListenerFactory based on express framework. + * + * When creating other server implementations, such as based on Koa. Should also create a NEW + * corresponding BlobKoaRequestListenerFactory class by extending IRequestListenerFactory. + * + * @export + * @class DataLakeRequestListenerFactory + * @implements {IRequestListenerFactory} + */ +export default class DataLakeRequestListenerFactory + implements IRequestListenerFactory +{ + public constructor( + private readonly metadataStore: IDataLakeMetaDataStore, + private readonly extentStore: IExtentStore, + private readonly accountDataStore: IAccountDataStore, + private readonly enableAccessLog: boolean, + private readonly accessLogWriteStream?: NodeJS.WritableStream, + private readonly loose?: boolean, + private readonly skipApiVersionCheck?: boolean, + private readonly oauth?: OAuthLevel, + private readonly disableProductStyleUrl?: boolean + ) {} + + public createRequestListener(): RequestListener { + const app = express().disable("x-powered-by"); + + // MiddlewareFactory is a factory to create auto-generated middleware + const middlewareFactory: MiddlewareFactory = new ExpressMiddlewareFactory( + logger, + DEFAULT_CONTEXT_PATH + ); + + // Create handlers into handler middleware factory + const pageBlobRangesManager = new PageBlobRangesManager(); + + const loose = this.loose || false; + const handlers: IHandlers = { + appendBlobHandler: new AppendBlobHandler( + this.metadataStore, + this.extentStore, + logger, + loose + ), + blobHandler: new BlobHandler( + this.metadataStore, + this.extentStore, + logger, + loose, + pageBlobRangesManager + ), + blockBlobHandler: new BlockBlobHandler( + this.metadataStore, + this.extentStore, + logger, + loose + ), + containerHandler: new ContainerHandler( + this.accountDataStore, + this.oauth, + this.metadataStore, + this.extentStore, + logger, + loose + ), + pageBlobHandler: new PageBlobHandler( + this.metadataStore, + this.extentStore, + logger, + loose, + pageBlobRangesManager + ), + serviceHandler: new ServiceHandler( + this.accountDataStore, + this.oauth, + this.metadataStore, + this.extentStore, + logger, + loose + ), + fileSystemOperationsHandler: new FileSystemOperationsHandler( + new ContainerHandler( + this.accountDataStore, + this.oauth, + this.metadataStore, + this.extentStore, + logger, + loose + ), + this.metadataStore, + this.extentStore, + logger, + loose + ), + pathOperationsHandler: new PathOperationsHandler( + new BlobHandler( + this.metadataStore, + this.extentStore, + logger, + loose, + pageBlobRangesManager + ), + this.metadataStore, + this.extentStore, + logger, + loose + ) + }; + + // CORS request handling, preflight request and the corresponding actual request + const preflightMiddlewareFactory = new PreflightMiddlewareFactory(logger); + + // Strict mode unsupported features blocker + const strictModelMiddlewareFactory = new StrictModelMiddlewareFactory( + logger, + [UnsupportedHeadersBlocker, UnsupportedParametersBlocker] + ); + + /* + * Generated middleware should follow strict orders + * Manually created middleware can be injected into any points + */ + + // Access log per request + if (this.enableAccessLog) { + app.use(morgan("common", { stream: this.accessLogWriteStream })); + } + + // Manually created middleware to deserialize feature related context which swagger doesn"t know + app.use( + createStorageBlobContextMiddleware( + this.skipApiVersionCheck, + this.disableProductStyleUrl, + this.loose + ) + ); + + // Dispatch incoming HTTP request to specific operation + app.use(middlewareFactory.createDispatchMiddleware()); + + // Block unsupported features in strict mode by default + if (this.loose === false || this.loose === undefined) { + app.use(strictModelMiddlewareFactory.createStrictModelMiddleware()); + } + + // AuthN middleware, like shared key auth or SAS auth + const authenticationMiddlewareFactory = new AuthenticationMiddlewareFactory( + logger + ); + const authenticators: IAuthenticator[] = [ + new PublicAccessAuthenticator(this.metadataStore, logger), + new BlobSharedKeyAuthenticator(this.accountDataStore, logger), + new AccountSASAuthenticator( + this.accountDataStore, + this.metadataStore, + logger + ), + new BlobSASAuthenticator( + this.accountDataStore, + this.metadataStore, + logger + ) + ]; + if (this.oauth !== undefined) { + authenticators.push( + new BlobTokenAuthenticator(this.accountDataStore, this.oauth, logger) + ); + } + app.use( + authenticationMiddlewareFactory.createAuthenticationMiddleware( + authenticators + ) + ); + + // Generated, will do basic validation defined in swagger + app.use(middlewareFactory.createDeserializerMiddleware()); + + // Generated, inject handlers to create a handler middleware + app.use(middlewareFactory.createHandlerMiddleware(handlers)); + + // CORS + app.use( + preflightMiddlewareFactory.createCorsRequestMiddleware( + this.metadataStore, + true + ) + ); + app.use( + preflightMiddlewareFactory.createCorsRequestMiddleware( + this.metadataStore, + false + ) + ); + + // Generated, will serialize response models into HTTP response + app.use(middlewareFactory.createSerializerMiddleware()); + + // Preflight + app.use( + preflightMiddlewareFactory.createOptionsHandlerMiddleware( + this.metadataStore + ) + ); + + // Generated, will return MiddlewareError and Errors thrown in previous middleware/handlers to HTTP response + app.use(middlewareFactory.createErrorMiddleware()); + + // Generated, will end and return HTTP response immediately + app.use(middlewareFactory.createEndMiddleware()); + + return app; + } +} diff --git a/src/dfs/DataLakeServer.ts b/src/dfs/DataLakeServer.ts new file mode 100644 index 000000000..ccfb70202 --- /dev/null +++ b/src/dfs/DataLakeServer.ts @@ -0,0 +1,39 @@ +import ICleaner from "../common/ICleaner"; +import LokiDataLakeMetadataStore from "./persistence/LokiDataLakeMetadataStore"; +import DataLakeRequestListenerFactory from "./DataLakeRequestListenerFactory"; +import BlobConfiguration from "../blob/BlobConfiguration"; +import { DEFAULT_DATA_LAKE_LISTENING_PORT, DEFAULT_DATA_LAKE_SERVER_HOST_NAME } from "./utils/constants"; +import BlobServer from "../blob/BlobServer"; + + +/** + * Default implementation of Azurite DataLake HTTP server. + * This implementation provides a HTTP service based on express framework and LokiJS in memory database. + * + * We can create other DataLake servers by extending abstract Server class and initialize different httpServer, + * dataStore or requestListenerFactory fields. + * + * For example, creating a HTTPS server to accept HTTPS requests, or using other + * Node.js HTTP frameworks like Koa, or just using another SQL database. + * + * @export + * @class Server + */ +export default class DataLakeServer extends BlobServer implements ICleaner { + /** + * Creates an instance of Server. + * + * @param {BlobConfiguration} configuration + * @memberof Server + */ + constructor(configuration?: BlobConfiguration) { + if (configuration === undefined) { + configuration = new BlobConfiguration( + DEFAULT_DATA_LAKE_SERVER_HOST_NAME, + DEFAULT_DATA_LAKE_LISTENING_PORT + ); + } + + super(configuration, LokiDataLakeMetadataStore, DataLakeRequestListenerFactory, "DataLake"); + } +} diff --git a/src/dfs/DataLakeServerFactory.ts b/src/dfs/DataLakeServerFactory.ts new file mode 100644 index 000000000..d62d2eb16 --- /dev/null +++ b/src/dfs/DataLakeServerFactory.ts @@ -0,0 +1,32 @@ +import DataLakeServer from "./DataLakeServer"; +import SqlDataLakeServer from "./SqlDataLakeServer"; +import { + DEFAULT_DATA_LAKE_EXTENT_LOKI_DB_PATH, + DEFAULT_DATA_LAKE_LISTENING_PORT, + DEFAULT_DATA_LAKE_LOKI_DB_PATH, + DEFAULT_DATA_LAKE_PERSISTENCE_ARRAY, + DEFAULT_DATA_LAKE_PERSISTENCE_PATH, + DEFAULT_DATA_LAKE_SERVER_HOST_NAME} from "./utils/constants"; +import IBlobEnvironment from "../blob/IBlobEnvironment"; +import { BlobServerFactory } from "../blob/BlobServerFactory"; + +export class DataLakeServerFactory extends BlobServerFactory { + public override async createServer( + blobEnvironment?: IBlobEnvironment + ): Promise { + return this.createActualServer( + blobEnvironment, + DEFAULT_DATA_LAKE_PERSISTENCE_ARRAY, + DEFAULT_DATA_LAKE_PERSISTENCE_PATH, + "AZURITE_DATALAKE_DB", + DEFAULT_DATA_LAKE_SERVER_HOST_NAME, + DEFAULT_DATA_LAKE_LISTENING_PORT, + DEFAULT_DATA_LAKE_LOKI_DB_PATH, + DEFAULT_DATA_LAKE_EXTENT_LOKI_DB_PATH, + SqlDataLakeServer, + DataLakeServer, + "datalakeHost", + "datalakePort" + ); + } +} diff --git a/src/dfs/SqlDataLakeServer.ts b/src/dfs/SqlDataLakeServer.ts new file mode 100644 index 000000000..c4180ac36 --- /dev/null +++ b/src/dfs/SqlDataLakeServer.ts @@ -0,0 +1,31 @@ + +import DataLakeRequestListenerFactory from "./DataLakeRequestListenerFactory"; +import SqlDataLakeMetadataStore from "./persistence/SqlDataLakeMetadataStore"; +import SqlBlobConfiguration from "../blob/SqlBlobConfiguration"; +import SqlBlobServer from "../blob/SqlBlobServer"; + + +/** + * Default implementation of Azurite DataLake HTTP server. + * This implementation provides a HTTP service based on express framework and LokiJS in memory database. + * + * We can create other DataLake servers by extending abstract Server class and initialize different httpServer, + * dataStore or requestListenerFactory fields. + * + * For example, creating a HTTPS server to accept HTTPS requests, or using other + * Node.js HTTP frameworks like Koa, or just using another SQL database. + * + * @export + * @class Server + */ +export default class SqlDataLakeServer extends SqlBlobServer { + /** + * Creates an instance of Server. + * + * @param {BlobConfiguration} configuration + * @memberof Server + */ + constructor(configuration: SqlBlobConfiguration) { + super(configuration, SqlDataLakeMetadataStore, DataLakeRequestListenerFactory, "DataLake"); + } +} \ No newline at end of file diff --git a/src/dfs/authentication/AccountSASAuthenticator.ts b/src/dfs/authentication/AccountSASAuthenticator.ts new file mode 100644 index 000000000..81315ef4e --- /dev/null +++ b/src/dfs/authentication/AccountSASAuthenticator.ts @@ -0,0 +1,33 @@ +import Operation from "../generated/artifacts/operation"; +import Context from "../../blob/generated/Context"; +import IAuthenticator from "./IAuthenticator"; +import BlobAccountSASAuthenticator from "../../blob/authentication/AccountSASAuthenticator" +import OPERATION_ACCOUNT_SAS_PERMISSIONS from "./OperationAccountSASPermission"; +import BLOB_OPERATION_ACCOUNT_SAS_PERMISSIONS, { OperationAccountSASPermission } from "../../blob/authentication/OperationAccountSASPermission"; + +export default class AccountSASAuthenticator extends BlobAccountSASAuthenticator implements IAuthenticator { + + protected override isSpecialPermissions(context: Context): boolean { + const operation: Operation = context.context.dfsOperation!; + //Blob + return operation === Operation.BlockBlob_Upload || + operation === Operation.PageBlob_Create || + operation === Operation.AppendBlob_Create || + operation === Operation.Blob_StartCopyFromURL || + operation === Operation.Blob_CopyFromURL || + //DataLake + operation === Operation.Path_Create || + operation === Operation.Path_AppendData || + operation === Operation.Path_FlushData + } + + protected override getOperationAccountSASPermission(context: Context): OperationAccountSASPermission | undefined { + const operation = BLOB_OPERATION_ACCOUNT_SAS_PERMISSIONS.get(context.operation!); + if (operation !== undefined) return operation; + return OPERATION_ACCOUNT_SAS_PERMISSIONS.get(context.context.dfsOperation!); + } + + protected override getOperationString(context: Context): string { + return Operation[context.context.dfsOperation!] + } +} diff --git a/src/dfs/authentication/BlobSASAuthenticator.ts b/src/dfs/authentication/BlobSASAuthenticator.ts new file mode 100644 index 000000000..9f6358fe5 --- /dev/null +++ b/src/dfs/authentication/BlobSASAuthenticator.ts @@ -0,0 +1,48 @@ +import Operation from "../generated/artifacts/operation"; +import Context from "../../blob/generated/Context"; +import { BlobSASResourceType } from "../../blob/authentication/BlobSASResourceType"; +import IAuthenticator from "./IAuthenticator"; +import { + OPERATION_BLOB_SAS_BLOB_PERMISSIONS, + OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS +} from "./OperationBlobSASPermission"; +import { + OPERATION_BLOB_SAS_BLOB_PERMISSIONS as BLOB_OPERATION_BLOB_SAS_BLOB_PERMISSIONS, + OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS as BLOB_OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS +} from "../../blob/authentication/OperationBlobSASPermission"; +import BlobBlobSASAuthenticator from "../../blob/authentication/BlobSASAuthenticator"; +import { OperationBlobSASPermission } from "../../blob/authentication/OperationBlobSASPermission"; + +export default class BlobSASAuthenticator extends BlobBlobSASAuthenticator implements IAuthenticator { + + protected override isSpecialPermissions(context: Context): boolean { + const operation: Operation = context.context.dfsOperation!; + //Blob + return operation === Operation.BlockBlob_Upload || + operation === Operation.PageBlob_Create || + operation === Operation.AppendBlob_Create || + operation === Operation.Blob_StartCopyFromURL || + operation === Operation.Blob_CopyFromURL || + //DataLake + operation === Operation.Path_Create || + operation === Operation.Path_AppendData || + operation === Operation.Path_FlushData + } + + protected override getOperationBlobSASPermission( + resource: BlobSASResourceType, + context: Context + ): OperationBlobSASPermission | undefined { + const permission = resource === BlobSASResourceType.Blob + ? BLOB_OPERATION_BLOB_SAS_BLOB_PERMISSIONS.get(context.operation!) + : BLOB_OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.get(context.operation!); + if (permission !== undefined) return permission; + return resource === BlobSASResourceType.Blob + ? OPERATION_BLOB_SAS_BLOB_PERMISSIONS.get(context.context.dfsOperation!) + : OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.get(context.context.dfsOperation!); + } + + protected override getOperationString(context: Context): string { + return Operation[context.context.dfsOperation!] + } +} diff --git a/src/dfs/authentication/BlobSharedKeyAuthenticator.ts b/src/dfs/authentication/BlobSharedKeyAuthenticator.ts new file mode 100644 index 000000000..3be73ab6a --- /dev/null +++ b/src/dfs/authentication/BlobSharedKeyAuthenticator.ts @@ -0,0 +1,4 @@ +import BlobBlobSharedKeyAuthenticator from "../../blob/authentication/BlobSharedKeyAuthenticator"; +import IAuthenticator from "./IAuthenticator"; + +export default class BlobSharedKeyAuthenticator extends BlobBlobSharedKeyAuthenticator implements IAuthenticator {} diff --git a/src/dfs/authentication/BlobTokenAuthenticator.ts b/src/dfs/authentication/BlobTokenAuthenticator.ts new file mode 100644 index 000000000..52f2f377f --- /dev/null +++ b/src/dfs/authentication/BlobTokenAuthenticator.ts @@ -0,0 +1,9 @@ +import { VALID_DATALAKE_AUDIENCES } from "../utils/constants"; +import IAuthenticator from "./IAuthenticator"; +import BlobBlobTokenAuthenticator from "../../blob/authentication/BlobTokenAuthenticator"; + +export default class BlobTokenAuthenticator extends BlobBlobTokenAuthenticator implements IAuthenticator { + + protected override getValidAudiences(): RegExp[] { + return VALID_DATALAKE_AUDIENCES; + }} diff --git a/src/dfs/authentication/IAuthenticator.ts b/src/dfs/authentication/IAuthenticator.ts new file mode 100644 index 000000000..312feda2c --- /dev/null +++ b/src/dfs/authentication/IAuthenticator.ts @@ -0,0 +1,6 @@ +import IRequest from "../../blob/generated/IRequest"; +import Context from "../../blob/generated/Context"; + +export default interface IAuthenticator { + validate(req: IRequest, content: Context): Promise; +} diff --git a/src/dfs/authentication/OperationAccountSASPermission.ts b/src/dfs/authentication/OperationAccountSASPermission.ts new file mode 100644 index 000000000..ab49f689b --- /dev/null +++ b/src/dfs/authentication/OperationAccountSASPermission.ts @@ -0,0 +1,200 @@ +import Operation from "../generated/artifacts/operation"; +import { AccountSASPermission } from "../../common/authentication/AccountSASPermissions"; +import { AccountSASResourceType } from "../../common/authentication/AccountSASResourceTypes"; +import { AccountSASService } from "../../common/authentication/AccountSASServices"; +import { OperationAccountSASPermission } from "../../blob/authentication/OperationAccountSASPermission"; + +// See https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-an-account-sas +// TODO: Check all required operations +const OPERATION_ACCOUNT_SAS_PERMISSIONS = new Map< + Operation, + OperationAccountSASPermission +>(); +///////////////////////////////// DataLake //////////////////////////////////// + +//////////////////////////////////Paths Operations////////////////////////////// +OPERATION_ACCOUNT_SAS_PERMISSIONS.set( + Operation.Path_Create, + new OperationAccountSASPermission( + AccountSASService.Blob, + AccountSASResourceType.Object, + AccountSASPermission.Create + AccountSASPermission.Write + ) +); + +OPERATION_ACCOUNT_SAS_PERMISSIONS.set( + Operation.Path_AppendData, + new OperationAccountSASPermission( + AccountSASService.Blob, + AccountSASResourceType.Object, + AccountSASPermission.Create + AccountSASPermission.Write + ) +); + +OPERATION_ACCOUNT_SAS_PERMISSIONS.set( + Operation.Path_FlushData, + new OperationAccountSASPermission( + AccountSASService.Blob, + AccountSASResourceType.Object, + AccountSASPermission.Write + ) +); + +OPERATION_ACCOUNT_SAS_PERMISSIONS.set( + Operation.Path_Lease, + new OperationAccountSASPermission( + AccountSASService.Blob, + AccountSASResourceType.Object, + AccountSASPermission.Write + ) +); + +OPERATION_ACCOUNT_SAS_PERMISSIONS.set( + Operation.Path_SetAccessControl, + new OperationAccountSASPermission( + AccountSASService.Blob, + AccountSASResourceType.Object, + AccountSASPermission.Write + ) +); + +OPERATION_ACCOUNT_SAS_PERMISSIONS.set( + Operation.Path_SetAccessControlRecursive, + new OperationAccountSASPermission( + AccountSASService.Blob, + AccountSASResourceType.Object, + AccountSASPermission.Write + ) +); + +OPERATION_ACCOUNT_SAS_PERMISSIONS.set( + Operation.Path_SetExpiry, + new OperationAccountSASPermission( + AccountSASService.Blob, + AccountSASResourceType.Object, + AccountSASPermission.Write + ) +); + +OPERATION_ACCOUNT_SAS_PERMISSIONS.set( + Operation.Path_Update, + new OperationAccountSASPermission( + AccountSASService.Blob, + AccountSASResourceType.Object, + AccountSASPermission.Write + ) +); + +OPERATION_ACCOUNT_SAS_PERMISSIONS.set( + Operation.Path_Undelete, + new OperationAccountSASPermission( + AccountSASService.Blob, + AccountSASResourceType.Object, + AccountSASPermission.Write + AccountSASPermission.Create + ) +); + +OPERATION_ACCOUNT_SAS_PERMISSIONS.set( + Operation.Path_Read, + new OperationAccountSASPermission( + AccountSASService.Blob, + AccountSASResourceType.Object, + AccountSASPermission.Read + ) +); + +OPERATION_ACCOUNT_SAS_PERMISSIONS.set( + Operation.Path_GetProperties, + new OperationAccountSASPermission( + AccountSASService.Blob, + AccountSASResourceType.Object, + AccountSASPermission.Read + ) +); + +OPERATION_ACCOUNT_SAS_PERMISSIONS.set( + Operation.Path_Delete, + new OperationAccountSASPermission( + AccountSASService.Blob, + AccountSASResourceType.Object, + AccountSASPermission.Delete + ) +); + +//////////////////////////////////FileSystem Operations////////////////////////////// + +OPERATION_ACCOUNT_SAS_PERMISSIONS.set( + Operation.FileSystem_Create, + new OperationAccountSASPermission( + AccountSASService.Blob, + AccountSASResourceType.Container, + AccountSASPermission.Create + ) +); + +OPERATION_ACCOUNT_SAS_PERMISSIONS.set( + Operation.FileSystem_SetProperties, + new OperationAccountSASPermission( + AccountSASService.Blob, + AccountSASResourceType.Container, + AccountSASPermission.Write + ) +); + +OPERATION_ACCOUNT_SAS_PERMISSIONS.set( + Operation.FileSystem_GetProperties, + new OperationAccountSASPermission( + AccountSASService.Blob, + AccountSASResourceType.Container, + AccountSASPermission.Read + ) +); + +OPERATION_ACCOUNT_SAS_PERMISSIONS.set( + Operation.FileSystem_ListPaths, + new OperationAccountSASPermission( + AccountSASService.Blob, + AccountSASResourceType.Container, + AccountSASPermission.List + ) +); + +OPERATION_ACCOUNT_SAS_PERMISSIONS.set( + Operation.FileSystem_ListBlobFlatSegment, + new OperationAccountSASPermission( + AccountSASService.Blob, + AccountSASResourceType.Container, + AccountSASPermission.List + ) +); + +OPERATION_ACCOUNT_SAS_PERMISSIONS.set( + Operation.FileSystem_ListBlobHierarchySegment, + new OperationAccountSASPermission( + AccountSASService.Blob, + AccountSASResourceType.Container, + AccountSASPermission.List + ) +); + +OPERATION_ACCOUNT_SAS_PERMISSIONS.set( + Operation.FileSystem_Delete, + new OperationAccountSASPermission( + AccountSASService.Blob, + AccountSASResourceType.Container, + AccountSASPermission.Delete + ) +); + +//////////////////////////////////Service Operations////////////////////////////// + +OPERATION_ACCOUNT_SAS_PERMISSIONS.set( + Operation.Service_ListFileSystems, + new OperationAccountSASPermission( + AccountSASService.Blob, + AccountSASResourceType.Service, + AccountSASPermission.Delete + ) +); + +export default OPERATION_ACCOUNT_SAS_PERMISSIONS; diff --git a/src/dfs/authentication/OperationBlobSASPermission.ts b/src/dfs/authentication/OperationBlobSASPermission.ts new file mode 100644 index 000000000..793d108d6 --- /dev/null +++ b/src/dfs/authentication/OperationBlobSASPermission.ts @@ -0,0 +1,201 @@ +import Operation from "../generated/artifacts/operation"; +import { BlobSASPermission } from "../../blob/authentication/BlobSASPermissions"; +import { ContainerSASPermission } from "../../blob/authentication/ContainerSASPermissions"; +import { OperationBlobSASPermission } from "../../blob/authentication/OperationBlobSASPermission"; + +// See https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas +// Blob Service SAS Permissions for blob level +export const OPERATION_BLOB_SAS_BLOB_PERMISSIONS = new Map< + Operation, + OperationBlobSASPermission +>(); +///////////////////////////////// DataLake //////////////////////////////////// + +//////////////////////////////////Paths Operations////////////////////////////// +//Since it is used in rename as well it needs write +OPERATION_BLOB_SAS_BLOB_PERMISSIONS.set( + Operation.Path_Create, + new OperationBlobSASPermission( + BlobSASPermission.Create + BlobSASPermission.Write + ) +); +OPERATION_BLOB_SAS_BLOB_PERMISSIONS.set( + Operation.Path_AppendData, + new OperationBlobSASPermission(BlobSASPermission.Write) +); +OPERATION_BLOB_SAS_BLOB_PERMISSIONS.set( + Operation.Path_FlushData, + new OperationBlobSASPermission(BlobSASPermission.Write) +); +OPERATION_BLOB_SAS_BLOB_PERMISSIONS.set( + Operation.Path_Lease, + new OperationBlobSASPermission(BlobSASPermission.Write) +); +OPERATION_BLOB_SAS_BLOB_PERMISSIONS.set( + Operation.Path_SetAccessControl, + new OperationBlobSASPermission(BlobSASPermission.Write) +); +OPERATION_BLOB_SAS_BLOB_PERMISSIONS.set( + Operation.Path_SetAccessControlRecursive, + new OperationBlobSASPermission(BlobSASPermission.Write) +); +OPERATION_BLOB_SAS_BLOB_PERMISSIONS.set( + Operation.Path_SetExpiry, + new OperationBlobSASPermission(BlobSASPermission.Write) +); +OPERATION_BLOB_SAS_BLOB_PERMISSIONS.set( + Operation.Path_Update, + new OperationBlobSASPermission(BlobSASPermission.Write) +); +OPERATION_BLOB_SAS_BLOB_PERMISSIONS.set( + Operation.Path_Undelete, + new OperationBlobSASPermission( + BlobSASPermission.Write + BlobSASPermission.Create + ) +); +OPERATION_BLOB_SAS_BLOB_PERMISSIONS.set( + Operation.Path_Read, + new OperationBlobSASPermission(BlobSASPermission.Read) +); +OPERATION_BLOB_SAS_BLOB_PERMISSIONS.set( + Operation.Path_GetProperties, + new OperationBlobSASPermission(BlobSASPermission.Read) +); +OPERATION_BLOB_SAS_BLOB_PERMISSIONS.set( + Operation.Path_Delete, + new OperationBlobSASPermission(BlobSASPermission.Delete) +); +//////////////////////////////////FileSystem Operations////////////////////////////// + +OPERATION_BLOB_SAS_BLOB_PERMISSIONS.set( + Operation.FileSystem_Create, + new OperationBlobSASPermission() +); +OPERATION_BLOB_SAS_BLOB_PERMISSIONS.set( + Operation.FileSystem_SetProperties, + new OperationBlobSASPermission() +); +OPERATION_BLOB_SAS_BLOB_PERMISSIONS.set( + Operation.FileSystem_GetProperties, + new OperationBlobSASPermission() +); +OPERATION_BLOB_SAS_BLOB_PERMISSIONS.set( + Operation.FileSystem_ListPaths, + new OperationBlobSASPermission() +); +OPERATION_BLOB_SAS_BLOB_PERMISSIONS.set( + Operation.FileSystem_ListBlobFlatSegment, + new OperationBlobSASPermission() +); +OPERATION_BLOB_SAS_BLOB_PERMISSIONS.set( + Operation.FileSystem_ListBlobHierarchySegment, + new OperationBlobSASPermission() +); +OPERATION_BLOB_SAS_BLOB_PERMISSIONS.set( + Operation.FileSystem_Delete, + new OperationBlobSASPermission() +); +//////////////////////////////////Service Operations////////////////////////////// + +OPERATION_BLOB_SAS_BLOB_PERMISSIONS.set( + Operation.Service_ListFileSystems, + new OperationBlobSASPermission() +); + +// Blob Service SAS Permissions for container level +export const OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS = new Map< + Operation, + OperationBlobSASPermission +>(); +///////////////////////////////// DataLake //////////////////////////////////// + +//////////////////////////////////Paths Operations////////////////////////////// +//Since it is used in rename as well it needs write +OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set( + Operation.Path_Create, + new OperationBlobSASPermission( + BlobSASPermission.Create + BlobSASPermission.Write + ) +); +OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set( + Operation.Path_AppendData, + new OperationBlobSASPermission(BlobSASPermission.Write) +); +OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set( + Operation.Path_FlushData, + new OperationBlobSASPermission(BlobSASPermission.Write) +); +OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set( + Operation.Path_Lease, + new OperationBlobSASPermission(BlobSASPermission.Write) +); +OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set( + Operation.Path_SetAccessControl, + new OperationBlobSASPermission(BlobSASPermission.Write) +); +OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set( + Operation.Path_SetAccessControlRecursive, + new OperationBlobSASPermission(BlobSASPermission.Write) +); +OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set( + Operation.Path_SetExpiry, + new OperationBlobSASPermission(BlobSASPermission.Write) +); +OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set( + Operation.Path_Update, + new OperationBlobSASPermission(BlobSASPermission.Write) +); +OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set( + Operation.Path_Undelete, + new OperationBlobSASPermission( + BlobSASPermission.Write + BlobSASPermission.Create + ) +); +OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set( + Operation.Path_Read, + new OperationBlobSASPermission(BlobSASPermission.Read) +); +OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set( + Operation.Path_GetProperties, + new OperationBlobSASPermission(BlobSASPermission.Read) +); +OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set( + Operation.Path_Delete, + new OperationBlobSASPermission(BlobSASPermission.Delete) +); +//////////////////////////////////FileSystem Operations////////////////////////////// + +OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set( + Operation.FileSystem_Create, + new OperationBlobSASPermission(ContainerSASPermission.Create) +); +OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set( + Operation.FileSystem_SetProperties, + new OperationBlobSASPermission(ContainerSASPermission.Write) +); +OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set( + Operation.FileSystem_GetProperties, + new OperationBlobSASPermission(ContainerSASPermission.Read) +); +OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set( + Operation.FileSystem_ListPaths, + new OperationBlobSASPermission(ContainerSASPermission.List) +); +OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set( + Operation.FileSystem_ListBlobFlatSegment, + new OperationBlobSASPermission(ContainerSASPermission.List) +); +OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set( + Operation.FileSystem_ListBlobHierarchySegment, + new OperationBlobSASPermission(ContainerSASPermission.List) +); +OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set( + Operation.FileSystem_Delete, + new OperationBlobSASPermission(ContainerSASPermission.Delete) +); +//////////////////////////////////Service Operations////////////////////////////// + +OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set( + Operation.Service_ListFileSystems, + new OperationBlobSASPermission() +); diff --git a/src/dfs/authentication/PublicAccessAuthenticator.ts b/src/dfs/authentication/PublicAccessAuthenticator.ts new file mode 100644 index 000000000..5d3f0ebc4 --- /dev/null +++ b/src/dfs/authentication/PublicAccessAuthenticator.ts @@ -0,0 +1,46 @@ +import BlobPublicAccessAuthenticator from "../../blob/authentication/PublicAccessAuthenticator"; +import Operation from "../generated/artifacts/operation"; +import Context from "../../blob/generated/Context"; +import IAuthenticator from "./IAuthenticator"; + +const CONTAINER_PUBLIC_READ_OPERATIONS = new Set([ + //blob + Operation.Container_GetProperties, + Operation.Container_GetPropertiesWithHead, + Operation.Container_GetAccessPolicy, + Operation.PageBlob_GetPageRanges, // TODO: Not sure + Operation.PageBlob_GetPageRangesDiff, // TODO: Not sure + Operation.BlockBlob_GetBlockList, // TODO: Not sure + //DataLake + Operation.FileSystem_GetProperties, + Operation.FileSystem_ListBlobFlatSegment, + Operation.FileSystem_ListBlobHierarchySegment, + Operation.FileSystem_ListPaths, + Operation.Path_Read, + Operation.Path_GetProperties +]); + +const BLOB_PUBLIC_READ_OPERATIONS = new Set([ + //blob + Operation.PageBlob_GetPageRanges, // TODO: Not sure + Operation.PageBlob_GetPageRangesDiff, // TODO: Not sure + Operation.BlockBlob_GetBlockList, // TODO: Not sure + //DataLake + Operation.Path_Read, + Operation.Path_GetProperties +]); + +export default class PublicAccessAuthenticator extends BlobPublicAccessAuthenticator implements IAuthenticator { + + protected override isContainerPublicReadOperation(context: Context): boolean { + return CONTAINER_PUBLIC_READ_OPERATIONS.has(context.context.dfsOperation!) + } + + protected override isBlobPublicReadOperation(context: Context): boolean { + return BLOB_PUBLIC_READ_OPERATIONS.has(context.context.dfsOperation!); + } + + protected override getOperationString(context: Context): string { + return Operation[context.context.dfsOperation!] + } +} diff --git a/src/dfs/context/DataLakeContext.ts b/src/dfs/context/DataLakeContext.ts new file mode 100644 index 000000000..c63822b72 --- /dev/null +++ b/src/dfs/context/DataLakeContext.ts @@ -0,0 +1,81 @@ +import IAuthenticationContext from "../../blob/authentication/IAuthenticationContext"; +import Context from "../../blob/generated/Context"; + +export default class DataLakeContext + extends Context + implements IAuthenticationContext +{ + public get account(): string | undefined { + return this.context.account; + } + + public set account(account: string | undefined) { + this.context.account = account; + } + + public set isSecondary(isSecondary: boolean | undefined) { + this.context.isSecondary = isSecondary; + } + + public get isSecondary(): boolean | undefined { + return this.context.isSecondary; + } + + public get container(): string | undefined { + return this.context.container; + } + + public set container(container: string | undefined) { + this.context.container = container; + } + + public get blob(): string | undefined { + return this.context.blob; + } + + public set blob(blob: string | undefined) { + this.context.blob = blob; + } + + public get originalBlob(): string | undefined { + return this.context.originalBlob; + } + + public set originalBlob(originalBlob: string | undefined) { + this.context.originalBlob = originalBlob; + } + + public get authenticationPath(): string | undefined { + return this.context.authenticationPath; + } + + public set authenticationPath(path: string | undefined) { + this.context.authenticationPath = path; + } + + public get xMsRequestID(): string | undefined { + return this.contextId; + } + + public set xMsRequestID(xMsRequestID: string | undefined) { + this.contextId = xMsRequestID; + } + + public get disableProductStyleUrl(): boolean | undefined { + return this.context.disableProductStyleUrl; + } + + public set disableProductStyleUrl( + disableProductStyleUrl: boolean | undefined + ) { + this.context.disableProductStyleUrl = disableProductStyleUrl; + } + + public get loose(): boolean | undefined { + return this.context.loose; + } + + public set loose(loose: boolean | undefined) { + this.context.loose = loose; + } +} diff --git a/src/dfs/errors/DataLakeError.ts b/src/dfs/errors/DataLakeError.ts new file mode 100644 index 000000000..c7f21b0a3 --- /dev/null +++ b/src/dfs/errors/DataLakeError.ts @@ -0,0 +1,92 @@ +import MiddlewareError from "../../blob/generated/errors/MiddlewareError"; +import { jsonToXML } from "../../blob/generated/utils/xml"; +import Context from "../../blob/generated/Context"; +import { isDataLakeOperation } from "../utils/utils"; + +/** + * Represents an Azure Storage Server Error. + * + * @export + * @class StorageError + * @extends {MiddlewareError} + */ +export default class DataLakeError extends MiddlewareError { + public readonly errorCode: string; + public readonly errorMessage: string; + public readonly storageRequestID: string | undefined; + + /**isDataLakeOperation(context.context.dfsOperation!); + * Creates an instance of StorageError. + * + * @param {number} statusCode HTTP response status code + * @param {string} dataLakeErrorCode Azure DataLake error code, will be in response body and header + * @param {string} dataLakeErrorMessage Azure DataLake error message + * @param {string} blobErrorCode Azure Storage error code, will be in response body and header + * @param {string} blobErrorMessage Azure Storage error message + * @param {string} context The request Context + * @param {{ [key: string]: string }} [storageAdditionalErrorMessages={}] + * Additional error messages will be included in XML body + * @memberof StorageError + */ + constructor( + statusCode: number, + dataLakeErrorCode: string, + dataLakeErrorMessage: string, + blobErrorCode: string, + blobErrorMessage: string, + context: Context, + storageAdditionalErrorMessages: { [key: string]: string } = {} + ) { + const isDataLake = isDataLakeOperation(context); + const code = isDataLake ? dataLakeErrorCode : blobErrorCode; + const message = isDataLake ? dataLakeErrorMessage : blobErrorMessage; + const storageRequestID = context.contextId; + + let bodyInJSON: any = { + code, + message: `${message}\nRequestId:${storageRequestID}\nTime:${new Date().toISOString()}` + }; + + for (const key in storageAdditionalErrorMessages) { + if (storageAdditionalErrorMessages.hasOwnProperty(key)) { + const element = storageAdditionalErrorMessages[key]; + bodyInJSON[key] = element; + } + } + + bodyInJSON = { + message: `${message}\nRequestId:${storageRequestID}\nTime:${new Date().toISOString()}`, + code, + errorCode: code, + error: bodyInJSON + }; + + for (const key in storageAdditionalErrorMessages) { + if (storageAdditionalErrorMessages.hasOwnProperty(key)) { + const element = storageAdditionalErrorMessages[key]; + bodyInJSON[key] = element; + } + } + + const bodyInXML = jsonToXML(bodyInJSON); + + super( + statusCode, + message, + code, + { + "x-ms-error-code": dataLakeErrorCode, + "x-ms-request-id": storageRequestID + }, + // bodyInJSON, + // "application/json" + bodyInXML, + "application/xml" + ); + + this.name = "StorageError"; + this.errorCode = code; + this.errorMessage = message; + this.storageRequestID = storageRequestID; + } +} diff --git a/src/dfs/errors/NotImplementedError.ts b/src/dfs/errors/NotImplementedError.ts new file mode 100644 index 000000000..23e1059e3 --- /dev/null +++ b/src/dfs/errors/NotImplementedError.ts @@ -0,0 +1,22 @@ +import Context from "../../blob/generated/Context"; +import DataLakeError from "./DataLakeError"; + +/** + * Create customized error types by inheriting ServerError + * + * @export + * @class UnimplementedError + * @extends {DataLakeError} + */ +export default class NotImplementedError extends DataLakeError { + public constructor(context: Context) { + super( + 500, + "APINotImplemented", + "Current API is not implemented yet. Please vote your wanted features to https://github.com/azure/azurite/issues", + "APINotImplemented", + "Current API is not implemented yet. Please vote your wanted features to https://github.com/azure/azurite/issues", + context + ); + } +} diff --git a/src/dfs/errors/StorageErrorFactory.ts b/src/dfs/errors/StorageErrorFactory.ts new file mode 100644 index 000000000..3e784c27e --- /dev/null +++ b/src/dfs/errors/StorageErrorFactory.ts @@ -0,0 +1,338 @@ +import Context from "../../blob/generated/Context"; +import DataLakeError from "./DataLakeError"; + +const codeMap: Map = new Map(); +const errorMsgMap: Map = new Map(); + +codeMap.set("ContainerNotFound", "FilesystemNotFound"); +codeMap.set("RequestEntityTooLarge", "RequestBodyTooLarge"); +codeMap.set("ContainerAlreadyExists", "FilesystemAlreadyExists"); +codeMap.set("BlobAlreadyExists", "PathAlreadyExists"); +codeMap.set("BlobNotFound", "PathNotFound"); +codeMap.set("LeaseIdMismatchWithContainerOperation", "LeaseIdMismatchWithLeaseOperation"); +codeMap.set("LeaseIdMismatchWithBlobOperation", "LeaseIdMismatchWithLeaseOperation" ); +codeMap.set("LeaseNotPresentWithContainerOperation", "LeaseNotPresentWithLeaseOperation"); +codeMap.set("LeaseNotPresentWithBlobOperation", "LeaseNotPresentWithLeaseOperation"); + +errorMsgMap.set("FilesystemNotFound", "The specified filesystem does not exist."); +errorMsgMap.set("RequestBodyTooLarge", "The request body is too large and exceeds the maximum permissible limit"); +errorMsgMap.set("FilesystemAlreadyExists", "The specified filesystem already exists."); +errorMsgMap.set("PathAlreadyExists", "The specified path already exists."); +errorMsgMap.set("PathNotFound", "The specified path does not exist."); +errorMsgMap.set("LeaseIsBreakingAndCannotBeAcquired", "The lease ID matched, but the lease is currently in breaking state and cannot be acquired until it is broken."); +errorMsgMap.set("LeaseNotPresentWithLeaseOperation", "The lease ID is not present with the specified lease operation."); +errorMsgMap.set("LeaseIdMismatchWithLeaseOperation", "The lease ID specified did not match the lease ID for the resource with the specified lease operation."); +errorMsgMap.set("LeaseIdMissing", "There is currently a lease on the resource and no lease ID was specified in the request."); +errorMsgMap.set("LeaseIdMismatchWithLeaseOperation", "The lease ID specified did not match the lease ID for the resource with the specified lease operation."); +errorMsgMap.set("LeaseNotPresentWithLeaseOperation", "The lease ID is not present with the specified lease operation."); +errorMsgMap.set("OutOfRangeInput", "One of the request inputs is out of range."); + +/** + * A factory class maintains all Azure Storage Blob service errors. + * + * @export + * @class DataLakeErrorFactory + */ +export default class DataLakeErrorFactory { + public static blobErrorToDfsError( + errorCode: string, + errorMsg: string + ): [string, string] { + const mappedErrorCode = codeMap.get(errorCode); + const newErrorCode = mappedErrorCode ? mappedErrorCode : errorCode; + const mappedErrorMsg = errorMsgMap.get(newErrorCode); + const newErrorMsg = mappedErrorMsg ? mappedErrorMsg : errorMsg; + return [newErrorCode, newErrorMsg]; + } + + public static getContainerNotFound(context: Context): DataLakeError { + return new DataLakeError( + 404, + "FilesystemNotFound", + "The specified filesystem does not exist.", + "ContainerNotFound", + "The specified container does not exist.", + context + ); + } + + public static getRequestEntityTooLarge(context: Context): DataLakeError { + return new DataLakeError( + 413, + "RequestBodyTooLarge", + "The request body is too large and exceeds the maximum permissible limit", + "RequestEntityTooLarge", + "The uploaded entity blob is too large.", + context + ); + } + + //TODO: check code/message for datalake + public static getBlockCountExceedsLimit(context: Context): DataLakeError { + return new DataLakeError( + 409, + "BlockCountExceedsLimit", + "The committed block count cannot exceed the maximum limit of 50,000 blocks.", + "BlockCountExceedsLimit", + "The committed block count cannot exceed the maximum limit of 50,000 blocks.", + context + ); + } + + public static getBlobAlreadyExists(context: Context): DataLakeError { + return new DataLakeError( + 409, + "PathAlreadyExists", + "The specified path already exists.", + "BlobAlreadyExists", + "The specified blob already exists.", + context + ); + } + + public static getBlobNotFound(context: Context): DataLakeError { + return new DataLakeError( + 404, + "PathNotFound", + "The specified path does not exist.", + "BlobNotFound", + "The specified blob does not exist.", + context + ); + } + + public static getInvalidQueryParameterValue( + context: Context, + parameterName?: string, + parameterValue?: string, + reason?: string + ): DataLakeError { + const additionalMessages: { + [key: string]: string; + } = {}; + + if (parameterName) { + additionalMessages.QueryParameterName = parameterName; + } + + if (parameterValue) { + additionalMessages.QueryParameterValue = parameterValue; + } + + if (reason) { + additionalMessages.Reason = reason; + } + + return new DataLakeError( + 400, + "InvalidQueryParameterValue", + "Value for one of the query parameters specified in the request URI is invalid.", + "InvalidQueryParameterValue", + `Value for one of the query parameters specified in the request URI is invalid.`, + context, + additionalMessages + ); + } + + //TODO: get the right code/message for datalake + public static getInvalidOperation( + context: Context, + message: string = "" + ): DataLakeError { + return new DataLakeError( + 400, + "InvalidOperation", + message, + "InvalidOperation", + message, + context + ); + } + + //No Equivalent in DataLake + public static getInvalidBlockList(context: Context): DataLakeError { + return new DataLakeError( + 400, + "InvalidBlockList", + "The specified block list is invalid.", + "InvalidBlockList", + "The specified block list is invalid.", + context + ); + } + + //TODO: check the right code/message for datalake + public static getMd5Mismatch( + context: Context, + userSpecifiedMd5: string, + serverCalculatedMd5: string + ): DataLakeError { + return new DataLakeError( + 400, + "Md5Mismatch", + "The MD5 value specified in the request did not match with the MD5 value calculated by the server.", + "Md5Mismatch", + "The MD5 value specified in the request did not match with the MD5 value calculated by the server.", + context, + { + UserSpecifiedMd5: userSpecifiedMd5, + ServerCalculatedMd5: serverCalculatedMd5 + } + ); + } + + public static getLeaseNotPresentWithLeaseOperation( + context: Context + ): DataLakeError { + return new DataLakeError( + 409, + "LeaseNotPresentWithLeaseOperation", + "The lease ID is not present with the specified lease operation.", + "LeaseNotPresentWithLeaseOperation", + "There is currently no lease on the container or blob.", + context + ); + } + + public static getMissingRequestHeader(context: Context): DataLakeError { + return new DataLakeError( + 400, + "MissingRequiredHeader", + "An HTTP header that's mandatory for this request is not specified.", + "MissingRequiredHeader", + "An HTTP header that's mandatory for this request is not specified.", + context + ); + } + + public static getAuthorizationFailure(context: Context): DataLakeError { + return new DataLakeError( + 403, + "AuthorizationFailure", + "Server failed to authenticate the request. Make sure the value of the Authorization header is formed correctly including the signature.", + "AuthorizationFailure", + "Server failed to authenticate the request. Make sure the value of the Authorization header is formed correctly including the signature.", + context + ); + } + + public static getBlobInvalidBlobType(context: Context): DataLakeError { + return new DataLakeError( + 409, + "InvalidBlobType", + "The blob type is invalid for this operation.", + "InvalidBlobType", + "The blob type is invalid for this operation.", + context + ); + } + + public static getInvalidHeaderValue( + context: Context, + additionalMessages?: { [key: string]: string } + ): DataLakeError { + if (additionalMessages === undefined) { + additionalMessages = {}; + } + return new DataLakeError( + 400, + "InvalidHeaderValue", + "The value for one of the HTTP headers is not in the correct format.", + "InvalidHeaderValue", + "The value for one of the HTTP headers is not in the correct format.", + context, + additionalMessages + ); + } + + public static getInvalidAPIVersion( + context: Context, + apiVersion?: string + ): DataLakeError { + return new DataLakeError( + 400, + "InvalidHeaderValue", + `The API version ${apiVersion} is not supported by Azurite. Please upgrade Azurite to latest version and retry. If you are using Azurite in Visual Studio, please check you have installed latest Visual Studio patch. Azurite command line parameter \"--skipApiVersionCheck\" or Visual Studio Code configuration \"Skip Api Version Check\" can skip this error. `, + "InvalidHeaderValue", + `The API version ${apiVersion} is not supported by Azurite. Please upgrade Azurite to latest version and retry. If you are using Azurite in Visual Studio, please check you have installed latest Visual Studio patch. Azurite command line parameter \"--skipApiVersionCheck\" or Visual Studio Code configuration \"Skip Api Version Check\" can skip this error. `, + context + ); + } + + public static getInvalidCorsHeaderValue( + context: Context, + additionalMessages?: { [key: string]: string } + ): DataLakeError { + return new DataLakeError( + 400, + "InvalidHeaderValue", + "A required CORS header is not present.", + "InvalidHeaderValue", + "A required CORS header is not present.", + context, + additionalMessages + ); + } + + public static corsPreflightFailure( + context: Context, + additionalMessages?: { [key: string]: string } + ): DataLakeError { + return new DataLakeError( + 403, + "CorsPreflightFailure", + "CORS not enabled or no matching rule found for this request.", + "CorsPreflightFailure", + "CORS not enabled or no matching rule found for this request.", + context, + additionalMessages + ); + } + + public static getInvalidResourceName(context: Context): DataLakeError { + return new DataLakeError( + 400, + "InvalidResourceName", + "The specified resource name contains invalid characters.", + "InvalidResourceName", + "The specified resource name contains invalid characters.", + context + ); + } + + public static getOutOfRangeName(context: Context): DataLakeError { + return new DataLakeError( + 400, + "OutOfRangeInput", + "One of the request inputs is out of range.", + "OutOfRangeInput", + `The specified resource name length is not within the permissible limits.`, + context + ); + } + + public static getInvalidInput( + context: Context, + message: string + ): DataLakeError { + return new DataLakeError( + 400, + "InvalidInput", + message, + "InvalidInput", + message, + context + ); + } + + public static getPathConflict(context: Context) { + return new DataLakeError( + 409, + "PathConflict", + "The specified path, or an element of the path, exists and its resource type is invalid for this operation.", + "PathConflict", + "The specified path, or an element of the path, exists and its resource type is invalid for this operation.", + context + ); + } +} diff --git a/src/dfs/errors/StrictModelNotSupportedError.ts b/src/dfs/errors/StrictModelNotSupportedError.ts new file mode 100644 index 000000000..5b759818a --- /dev/null +++ b/src/dfs/errors/StrictModelNotSupportedError.ts @@ -0,0 +1,15 @@ +import Context from "../../blob/generated/Context"; +import DataLakeError from "./DataLakeError"; + +export default class StrictModelNotSupportedError extends DataLakeError { + public constructor(feature: string, context: Context) { + super( + 500, + "FeatureNotSupported", + `${feature} header or parameter is not supported in Azurite strict mode. Switch to loose model by Azurite command line parameter "--loose" or Visual Studio Code configuration "Loose". Please vote your wanted features to https://github.com/azure/azurite/issues`, + "FeatureNotSupported", + `${feature} header or parameter is not supported in Azurite strict mode. Switch to loose model by Azurite command line parameter "--loose" or Visual Studio Code configuration "Loose". Please vote your wanted features to https://github.com/azure/azurite/issues`, + context + ); + } +} diff --git a/src/dfs/generated/ExpressMiddlewareFactory.ts b/src/dfs/generated/ExpressMiddlewareFactory.ts new file mode 100644 index 000000000..edb665b72 --- /dev/null +++ b/src/dfs/generated/ExpressMiddlewareFactory.ts @@ -0,0 +1,143 @@ +import { ErrorRequestHandler, NextFunction, Request, RequestHandler, Response } from 'express'; + +import Context from '../../blob/generated/Context'; +import BlobContext from '../../blob/generated/Context'; +import deserializerMiddleware from './middleware/deserializer.middleware'; +import dispatchMiddleware from './middleware/dispatch.middleware'; +import HandlerMiddlewareFactory from './middleware/HandlerMiddlewareFactory'; +import serializerMiddleware from './middleware/serializer.middleware'; +import ExpressRequestAdapter from '../../blob/generated/ExpressRequestAdapter'; +import ExpressResponseAdapter from '../../blob/generated/ExpressResponseAdapter'; +import BlobExpressMiddlewareFactory from '../../blob/generated/ExpressMiddlewareFactory'; +import ILogger from '../../common/ILogger'; +import errorMiddleware from './middleware/error.middleware'; + +/** + * ExpressMiddlewareFactory will generate Express compatible middleware according to swagger definitions. + * Generated middleware MUST be used by strict order: + * * dispatchMiddleware + * * DeserializerMiddleware + * * HandlerMiddleware + * * SerializerMiddleware + * * ErrorMiddleware + * * EndMiddleware + * + * @export + * @class MiddlewareFactory + */ +export default class ExpressMiddlewareFactory extends BlobExpressMiddlewareFactory { + /** + * Creates an instance of MiddlewareFactory. + * + * @param {ILogger} logger A valid logger + * @param {string} [contextPath="default_context"] Optional. res.locals[contextPath] will be used to hold context + * @memberof MiddlewareFactory + */ + public constructor( + logger: ILogger, + private readonly dfsContextPath: string = "default_context" + ) { + super(logger, dfsContextPath); + } + + /** + * DispatchMiddleware is the 1s middleware should be used among other generated middleware. + * + * @returns {RequestHandler} + * @memberof MiddlewareFactory + */ + public createDispatchMiddleware(): RequestHandler { + return (req: Request, res: Response, next: NextFunction) => { + req.baseUrl + const request = new ExpressRequestAdapter(req); + const response = new ExpressResponseAdapter(res); + dispatchMiddleware( + new Context(res.locals, this.dfsContextPath, request, response), + request, + next, + this.logger + ); + }; + } + + /** + * DeserializerMiddleware is the 2nd middleware should be used among other generated middleware. + * + * @returns {RequestHandler} + * @memberof MiddlewareFactory + */ + public createDeserializerMiddleware(): RequestHandler { + return (req: Request, res: Response, next: NextFunction) => { + const request = new ExpressRequestAdapter(req); + const response = new ExpressResponseAdapter(res); + deserializerMiddleware( + new Context(res.locals, this.dfsContextPath, request, response), + request, + next, + this.logger + ); + }; + } + + /** + * HandlerMiddleware is the 3rd middleware should be used among other generated middleware. + * + * @param {IHandlers} handlers + * @returns {RequestHandler} + * @memberof MiddlewareFactory + */ + public createHandlerMiddleware(handlers: any): RequestHandler { + const handlerMiddlewareFactory = new HandlerMiddlewareFactory( + handlers, + this.logger + ); + return (req: Request, res: Response, next: NextFunction) => { + const request = new ExpressRequestAdapter(req); + const response = new ExpressResponseAdapter(res); + handlerMiddlewareFactory.createHandlerMiddleware()( + new Context(res.locals, this.dfsContextPath, request, response) as BlobContext, + next + ); + }; + } + + /** + * SerializerMiddleware is the 4st middleware should be used among other generated middleware. + * + * @returns {RequestHandler} + * @memberof MiddlewareFactory + */ + public createSerializerMiddleware(): RequestHandler { + return (req: Request, res: Response, next: NextFunction) => { + const request = new ExpressRequestAdapter(req); + const response = new ExpressResponseAdapter(res); + serializerMiddleware( + new Context(res.locals, this.dfsContextPath, request, response), + new ExpressResponseAdapter(res), + next, + this.logger + ); + }; + } + + /** + * ErrorMiddleware is the 5st middleware should be used among other generated middleware. + * + * @returns {ErrorRequestHandler} + * @memberof MiddlewareFactory + */ + public createErrorMiddleware(): ErrorRequestHandler { + return (err: Error, req: Request, res: Response, next: NextFunction) => { + const request = new ExpressRequestAdapter(req); + const response = new ExpressResponseAdapter(res); + errorMiddleware( + new Context(res.locals, this.dfsContextPath, request, response), + err, + new ExpressRequestAdapter(req), + new ExpressResponseAdapter(res), + next, + this.logger + ); + }; + } +} diff --git a/src/dfs/generated/artifacts/mappers.ts b/src/dfs/generated/artifacts/mappers.ts new file mode 100644 index 000000000..823433375 --- /dev/null +++ b/src/dfs/generated/artifacts/mappers.ts @@ -0,0 +1,8729 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ +// tslint:disable:object-literal-sort-keys + +import * as msRest from "@azure/ms-rest-js"; + +export const AclFailedEntry: msRest.CompositeMapper = { + serializedName: "AclFailedEntry", + type: { + name: "Composite", + className: "AclFailedEntry", + modelProperties: { + name: { + xmlName: "name", + serializedName: "name", + type: { + name: "String" + } + }, + type: { + xmlName: "type", + serializedName: "type", + type: { + name: "String" + } + }, + errorMessage: { + xmlName: "errorMessage", + serializedName: "errorMessage", + type: { + name: "String" + } + } + } + } +}; + +export const SetAccessControlRecursiveResponse: msRest.CompositeMapper = { + serializedName: "SetAccessControlRecursiveResponse", + type: { + name: "Composite", + className: "SetAccessControlRecursiveResponse", + modelProperties: { + directoriesSuccessful: { + xmlName: "directoriesSuccessful", + serializedName: "directoriesSuccessful", + type: { + name: "Number" + } + }, + filesSuccessful: { + xmlName: "filesSuccessful", + serializedName: "filesSuccessful", + type: { + name: "Number" + } + }, + failureCount: { + xmlName: "failureCount", + serializedName: "failureCount", + type: { + name: "Number" + } + }, + failedEntries: { + xmlName: "failedEntries", + xmlElementName: "AclFailedEntry", + serializedName: "failedEntries", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "AclFailedEntry" + } + } + } + } + } + } +}; + +export const Path: msRest.CompositeMapper = { + serializedName: "Path", + type: { + name: "Composite", + className: "Path", + modelProperties: { + name: { + xmlName: "name", + serializedName: "name", + type: { + name: "String" + } + }, + isDirectory: { + xmlName: "isDirectory", + serializedName: "isDirectory", + defaultValue: false, + type: { + name: "Boolean" + } + }, + lastModified: { + xmlName: "lastModified", + serializedName: "lastModified", + type: { + name: "DateTimeRfc1123" + } + }, + etag: { + xmlName: "etag", + serializedName: "etag", + type: { + name: "String" + } + }, + contentLength: { + xmlName: "contentLength", + serializedName: "contentLength", + type: { + name: "Number" + } + }, + owner: { + xmlName: "owner", + serializedName: "owner", + type: { + name: "String" + } + }, + group: { + xmlName: "group", + serializedName: "group", + type: { + name: "String" + } + }, + permissions: { + xmlName: "permissions", + serializedName: "permissions", + type: { + name: "String" + } + }, + encryptionScope: { + xmlName: "EncryptionScope", + serializedName: "EncryptionScope", + type: { + name: "String" + } + } + } + } +}; + +export const PathList: msRest.CompositeMapper = { + xmlName: "paths", + serializedName: "PathList", + type: { + name: "Composite", + className: "PathList", + modelProperties: { + paths: { + xmlName: "paths", + xmlElementName: "paths", + serializedName: "paths", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "Path" + } + } + } + } + } + } +}; + +export const FileSystem: msRest.CompositeMapper = { + serializedName: "FileSystem", + type: { + name: "Composite", + className: "FileSystem", + modelProperties: { + name: { + xmlName: "name", + serializedName: "name", + type: { + name: "String" + } + }, + lastModified: { + xmlName: "lastModified", + serializedName: "lastModified", + type: { + name: "String" + } + }, + eTag: { + xmlName: "eTag", + serializedName: "eTag", + type: { + name: "String" + } + } + } + } +}; + +export const BlobPropertiesInternal: msRest.CompositeMapper = { + xmlName: "Properties", + serializedName: "BlobPropertiesInternal", + type: { + name: "Composite", + className: "BlobPropertiesInternal", + modelProperties: { + creationTime: { + xmlName: "Creation-Time", + serializedName: "Creation-Time", + type: { + name: "DateTimeRfc1123" + } + }, + lastModified: { + xmlName: "Last-Modified", + required: true, + serializedName: "Last-Modified", + type: { + name: "DateTimeRfc1123" + } + }, + etag: { + xmlName: "Etag", + required: true, + serializedName: "Etag", + type: { + name: "String" + } + }, + contentLength: { + xmlName: "Content-Length", + serializedName: "Content-Length", + type: { + name: "Number" + } + }, + contentType: { + xmlName: "Content-Type", + serializedName: "Content-Type", + type: { + name: "String" + } + }, + contentEncoding: { + xmlName: "Content-Encoding", + serializedName: "Content-Encoding", + type: { + name: "String" + } + }, + contentLanguage: { + xmlName: "Content-Language", + serializedName: "Content-Language", + type: { + name: "String" + } + }, + contentMD5: { + xmlName: "Content-MD5", + serializedName: "Content-MD5", + type: { + name: "ByteArray" + } + }, + contentDisposition: { + xmlName: "Content-Disposition", + serializedName: "Content-Disposition", + type: { + name: "String" + } + }, + cacheControl: { + xmlName: "Cache-Control", + serializedName: "Cache-Control", + type: { + name: "String" + } + }, + blobSequenceNumber: { + xmlName: "x-ms-blob-sequence-number", + serializedName: "x-ms-blob-sequence-number", + type: { + name: "Number" + } + }, + copyId: { + xmlName: "CopyId", + serializedName: "CopyId", + type: { + name: "String" + } + }, + copySource: { + xmlName: "CopySource", + serializedName: "CopySource", + type: { + name: "String" + } + }, + copyProgress: { + xmlName: "CopyProgress", + serializedName: "CopyProgress", + type: { + name: "String" + } + }, + copyCompletionTime: { + xmlName: "CopyCompletionTime", + serializedName: "CopyCompletionTime", + type: { + name: "DateTimeRfc1123" + } + }, + copyStatusDescription: { + xmlName: "CopyStatusDescription", + serializedName: "CopyStatusDescription", + type: { + name: "String" + } + }, + serverEncrypted: { + xmlName: "ServerEncrypted", + serializedName: "ServerEncrypted", + type: { + name: "Boolean" + } + }, + incrementalCopy: { + xmlName: "IncrementalCopy", + serializedName: "IncrementalCopy", + type: { + name: "Boolean" + } + }, + destinationSnapshot: { + xmlName: "DestinationSnapshot", + serializedName: "DestinationSnapshot", + type: { + name: "String" + } + }, + deletedTime: { + xmlName: "DeletedTime", + serializedName: "DeletedTime", + type: { + name: "DateTimeRfc1123" + } + }, + remainingRetentionDays: { + xmlName: "RemainingRetentionDays", + serializedName: "RemainingRetentionDays", + type: { + name: "Number" + } + }, + accessTierInferred: { + xmlName: "AccessTierInferred", + serializedName: "AccessTierInferred", + type: { + name: "Boolean" + } + }, + customerProvidedKeySha256: { + xmlName: "CustomerProvidedKeySha256", + serializedName: "CustomerProvidedKeySha256", + type: { + name: "String" + } + }, + encryptionScope: { + xmlName: "EncryptionScope", + serializedName: "EncryptionScope", + type: { + name: "String" + } + }, + accessTierChangeTime: { + xmlName: "AccessTierChangeTime", + serializedName: "AccessTierChangeTime", + type: { + name: "DateTimeRfc1123" + } + }, + tagCount: { + xmlName: "TagCount", + serializedName: "TagCount", + type: { + name: "Number" + } + }, + expiresOn: { + xmlName: "Expiry-Time", + serializedName: "Expiry-Time", + type: { + name: "DateTimeRfc1123" + } + }, + isSealed: { + xmlName: "Sealed", + serializedName: "Sealed", + type: { + name: "Boolean" + } + }, + lastAccessedOn: { + xmlName: "LastAccessTime", + serializedName: "LastAccessTime", + type: { + name: "DateTimeRfc1123" + } + }, + deleteTime: { + xmlName: "DeleteTime", + serializedName: "DeleteTime", + type: { + name: "DateTimeRfc1123" + } + }, + properties: { + xmlName: "properties", + serializedName: "properties", + type: { + name: "String" + } + }, + blobType: { + xmlName: "BlobType", + serializedName: "BlobType", + type: { + name: "Enum", + allowedValues: [ + "BlockBlob", + "PageBlob", + "AppendBlob" + ] + } + }, + leaseStatus: { + xmlName: "LeaseStatus", + serializedName: "LeaseStatus", + type: { + name: "Enum", + allowedValues: [ + "locked", + "unlocked" + ] + } + }, + leaseState: { + xmlName: "LeaseState", + serializedName: "LeaseState", + type: { + name: "Enum", + allowedValues: [ + "available", + "leased", + "expired", + "breaking", + "broken" + ] + } + }, + leaseDuration: { + xmlName: "LeaseDuration", + serializedName: "LeaseDuration", + type: { + name: "Enum", + allowedValues: [ + "infinite", + "fixed" + ] + } + }, + copyStatus: { + xmlName: "CopyStatus", + serializedName: "CopyStatus", + type: { + name: "Enum", + allowedValues: [ + "pending", + "success", + "aborted", + "failed" + ] + } + }, + accessTier: { + xmlName: "AccessTier", + serializedName: "AccessTier", + type: { + name: "String" + } + }, + archiveStatus: { + xmlName: "ArchiveStatus", + serializedName: "ArchiveStatus", + type: { + name: "String" + } + }, + rehydratePriority: { + xmlName: "RehydratePriority", + serializedName: "RehydratePriority", + type: { + name: "String" + } + }, + immutabilityPolicyExpiresOn: { + xmlName: "ImmutabilityPolicyUntilDate", + serializedName: "ImmutabilityPolicyUntilDate", + type: { + name: "DateTimeRfc1123" + } + }, + immutabilityPolicyMode: { + xmlName: "ImmutabilityPolicyMode", + serializedName: "ImmutabilityPolicyMode", + type: { + name: "Enum", + allowedValues: [ + "Mutable", + "Unlocked", + "Locked" + ] + } + }, + legalHold: { + xmlName: "LegalHold", + serializedName: "LegalHold", + type: { + name: "Boolean" + } + } + } + } +}; + +export const BlobMetadata: msRest.CompositeMapper = { + xmlName: "Metadata", + serializedName: "BlobMetadata", + type: { + name: "Composite", + className: "BlobMetadata", + modelProperties: { + encrypted: { + xmlIsAttribute: true, + xmlName: "Encrypted", + serializedName: "Encrypted", + type: { + name: "String" + } + } + }, + additionalProperties: { + type: { + name: "String" + } + } + } +}; + +export const BlobTag: msRest.CompositeMapper = { + xmlName: "Tag", + serializedName: "BlobTag", + type: { + name: "Composite", + className: "BlobTag", + modelProperties: { + key: { + xmlName: "Key", + required: true, + serializedName: "Key", + type: { + name: "String" + } + }, + value: { + xmlName: "Value", + required: true, + serializedName: "Value", + type: { + name: "String" + } + } + } + } +}; + +export const BlobTags: msRest.CompositeMapper = { + xmlName: "Tags", + serializedName: "BlobTags", + type: { + name: "Composite", + className: "BlobTags", + modelProperties: { + blobTagSet: { + xmlIsWrapped: true, + xmlName: "TagSet", + xmlElementName: "Tag", + required: true, + serializedName: "BlobTagSet", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "BlobTag" + } + } + } + } + } + } +}; + +export const BlobItemInternal: msRest.CompositeMapper = { + xmlName: "Blob", + serializedName: "BlobItemInternal", + type: { + name: "Composite", + className: "BlobItemInternal", + modelProperties: { + name: { + xmlName: "Name", + required: true, + serializedName: "Name", + type: { + name: "String" + } + }, + deleted: { + xmlName: "Deleted", + serializedName: "Deleted", + type: { + name: "Boolean" + } + }, + snapshot: { + xmlName: "Snapshot", + serializedName: "Snapshot", + type: { + name: "String" + } + }, + versionId: { + xmlName: "VersionId", + serializedName: "VersionId", + type: { + name: "String" + } + }, + isCurrentVersion: { + xmlName: "IsCurrentVersion", + serializedName: "IsCurrentVersion", + type: { + name: "Boolean" + } + }, + properties: { + xmlName: "Properties", + required: true, + serializedName: "Properties", + type: { + name: "Composite", + className: "BlobPropertiesInternal" + } + }, + deletionId: { + xmlName: "DeletionId", + serializedName: "DeletionId", + type: { + name: "String" + } + }, + metadata: { + xmlName: "Metadata", + serializedName: "Metadata", + type: { + name: "Composite", + className: "BlobMetadata", + additionalProperties: { + type: { + name: "String" + } + } + } + }, + blobTags: { + xmlName: "Tags", + serializedName: "BlobTags", + type: { + name: "Composite", + className: "BlobTags" + } + }, + objectReplicationMetadata: { + xmlName: "OrMetadata", + serializedName: "ObjectReplicationMetadata", + type: { + name: "Dictionary", + value: { + type: { + name: "String" + } + } + } + }, + hasVersionsOnly: { + xmlName: "HasVersionsOnly", + serializedName: "HasVersionsOnly", + type: { + name: "Boolean" + } + } + } + } +}; + +export const BlobFlatListSegment: msRest.CompositeMapper = { + xmlName: "Blobs", + serializedName: "BlobFlatListSegment", + type: { + name: "Composite", + className: "BlobFlatListSegment", + modelProperties: { + blobItems: { + xmlName: "BlobItems", + xmlElementName: "Blob", + required: true, + serializedName: "BlobItems", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "BlobItemInternal" + } + } + } + } + } + } +}; + +export const ListBlobsFlatSegmentResponse: msRest.CompositeMapper = { + xmlName: "EnumerationResults", + serializedName: "ListBlobsFlatSegmentResponse", + type: { + name: "Composite", + className: "ListBlobsFlatSegmentResponse", + modelProperties: { + serviceEndpoint: { + xmlIsAttribute: true, + xmlName: "ServiceEndpoint", + required: true, + serializedName: "ServiceEndpoint", + type: { + name: "String" + } + }, + containerName: { + xmlIsAttribute: true, + xmlName: "ContainerName", + required: true, + serializedName: "ContainerName", + type: { + name: "String" + } + }, + prefix: { + xmlName: "Prefix", + serializedName: "Prefix", + type: { + name: "String" + } + }, + marker: { + xmlName: "Marker", + serializedName: "Marker", + type: { + name: "String" + } + }, + maxResults: { + xmlName: "MaxResults", + serializedName: "MaxResults", + type: { + name: "Number" + } + }, + segment: { + xmlName: "Blobs", + required: true, + serializedName: "Segment", + type: { + name: "Composite", + className: "BlobFlatListSegment" + } + }, + nextMarker: { + xmlName: "NextMarker", + serializedName: "NextMarker", + type: { + name: "String" + } + } + } + } +}; + +export const BlobPrefix: msRest.CompositeMapper = { + serializedName: "BlobPrefix", + type: { + name: "Composite", + className: "BlobPrefix", + modelProperties: { + name: { + xmlName: "Name", + required: true, + serializedName: "Name", + type: { + name: "String" + } + } + } + } +}; + +export const BlobHierarchyListSegment: msRest.CompositeMapper = { + xmlName: "Blobs", + serializedName: "BlobHierarchyListSegment", + type: { + name: "Composite", + className: "BlobHierarchyListSegment", + modelProperties: { + blobPrefixes: { + xmlName: "BlobPrefixes", + xmlElementName: "BlobPrefix", + serializedName: "BlobPrefixes", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "BlobPrefix" + } + } + } + }, + blobItems: { + xmlName: "BlobItems", + xmlElementName: "Blob", + required: true, + serializedName: "BlobItems", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "BlobItemInternal" + } + } + } + } + } + } +}; + +export const ListBlobsHierarchySegmentResponse: msRest.CompositeMapper = { + xmlName: "EnumerationResults", + serializedName: "ListBlobsHierarchySegmentResponse", + type: { + name: "Composite", + className: "ListBlobsHierarchySegmentResponse", + modelProperties: { + serviceEndpoint: { + xmlIsAttribute: true, + xmlName: "ServiceEndpoint", + required: true, + serializedName: "ServiceEndpoint", + type: { + name: "String" + } + }, + containerName: { + xmlIsAttribute: true, + xmlName: "ContainerName", + required: true, + serializedName: "ContainerName", + type: { + name: "String" + } + }, + prefix: { + xmlName: "Prefix", + serializedName: "Prefix", + type: { + name: "String" + } + }, + marker: { + xmlName: "Marker", + serializedName: "Marker", + type: { + name: "String" + } + }, + maxResults: { + xmlName: "MaxResults", + serializedName: "MaxResults", + type: { + name: "Number" + } + }, + delimiter: { + xmlName: "Delimiter", + serializedName: "Delimiter", + type: { + name: "String" + } + }, + segment: { + xmlName: "Blobs", + required: true, + serializedName: "Segment", + type: { + name: "Composite", + className: "BlobHierarchyListSegment" + } + }, + nextMarker: { + xmlName: "NextMarker", + serializedName: "NextMarker", + type: { + name: "String" + } + } + } + } +}; + +export const FileSystemList: msRest.CompositeMapper = { + serializedName: "FileSystemList", + type: { + name: "Composite", + className: "FileSystemList", + modelProperties: { + filesystems: { + xmlName: "filesystems", + xmlElementName: "FileSystem", + serializedName: "filesystems", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "FileSystem" + } + } + } + } + } + } +}; + +export const StorageErrorError: msRest.CompositeMapper = { + serializedName: "StorageError_error", + type: { + name: "Composite", + className: "StorageErrorError", + modelProperties: { + code: { + xmlName: "Code", + serializedName: "Code", + type: { + name: "String" + } + }, + message: { + xmlName: "Message", + serializedName: "Message", + type: { + name: "String" + } + } + } + } +}; + +export const StorageError: msRest.CompositeMapper = { + serializedName: "StorageError", + type: { + name: "Composite", + className: "StorageError", + modelProperties: { + message: { + xmlName: "Message", + serializedName: "Message", + type: { + name: "String" + } + }, + error: { + xmlName: "error", + serializedName: "error", + type: { + name: "Composite", + className: "StorageErrorError" + } + } + } + } +}; + +export const KeyInfo: msRest.CompositeMapper = { + serializedName: "KeyInfo", + type: { + name: "Composite", + className: "KeyInfo", + modelProperties: { + start: { + xmlName: "Start", + required: true, + serializedName: "Start", + type: { + name: "String" + } + }, + expiry: { + xmlName: "Expiry", + required: true, + serializedName: "Expiry", + type: { + name: "String" + } + } + } + } +}; + +export const UserDelegationKey: msRest.CompositeMapper = { + serializedName: "UserDelegationKey", + type: { + name: "Composite", + className: "UserDelegationKey", + modelProperties: { + signedOid: { + xmlName: "SignedOid", + required: true, + serializedName: "SignedOid", + type: { + name: "String" + } + }, + signedTid: { + xmlName: "SignedTid", + required: true, + serializedName: "SignedTid", + type: { + name: "String" + } + }, + signedStart: { + xmlName: "SignedStart", + required: true, + serializedName: "SignedStart", + type: { + name: "String" + } + }, + signedExpiry: { + xmlName: "SignedExpiry", + required: true, + serializedName: "SignedExpiry", + type: { + name: "String" + } + }, + signedService: { + xmlName: "SignedService", + required: true, + serializedName: "SignedService", + type: { + name: "String" + } + }, + signedVersion: { + xmlName: "SignedVersion", + required: true, + serializedName: "SignedVersion", + type: { + name: "String" + } + }, + value: { + xmlName: "Value", + required: true, + serializedName: "Value", + type: { + name: "String" + } + } + } + } +}; + +export const AccessPolicy: msRest.CompositeMapper = { + serializedName: "AccessPolicy", + type: { + name: "Composite", + className: "AccessPolicy", + modelProperties: { + start: { + xmlName: "Start", + serializedName: "Start", + type: { + name: "String" + } + }, + expiry: { + xmlName: "Expiry", + serializedName: "Expiry", + type: { + name: "String" + } + }, + permission: { + xmlName: "Permission", + serializedName: "Permission", + type: { + name: "String" + } + } + } + } +}; + +export const BlobName: msRest.CompositeMapper = { + serializedName: "BlobName", + type: { + name: "Composite", + className: "BlobName", + modelProperties: { + encoded: { + xmlIsAttribute: true, + xmlName: "Encoded", + serializedName: "Encoded", + type: { + name: "Boolean" + } + }, + content: { + xmlName: "content", + serializedName: "content", + type: { + name: "String" + } + } + } + } +}; + +export const Block: msRest.CompositeMapper = { + serializedName: "Block", + type: { + name: "Composite", + className: "Block", + modelProperties: { + name: { + xmlName: "Name", + required: true, + serializedName: "Name", + type: { + name: "String" + } + }, + size: { + xmlName: "Size", + required: true, + serializedName: "Size", + type: { + name: "Number" + } + } + } + } +}; + +export const BlockList: msRest.CompositeMapper = { + serializedName: "BlockList", + type: { + name: "Composite", + className: "BlockList", + modelProperties: { + committedBlocks: { + xmlIsWrapped: true, + xmlName: "CommittedBlocks", + xmlElementName: "Block", + serializedName: "CommittedBlocks", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "Block" + } + } + } + }, + uncommittedBlocks: { + xmlIsWrapped: true, + xmlName: "UncommittedBlocks", + xmlElementName: "Block", + serializedName: "UncommittedBlocks", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "Block" + } + } + } + } + } + } +}; + +export const BlockLookupList: msRest.CompositeMapper = { + xmlName: "BlockList", + serializedName: "BlockLookupList", + type: { + name: "Composite", + className: "BlockLookupList", + modelProperties: { + committed: { + xmlName: "Committed", + xmlElementName: "Committed", + serializedName: "Committed", + type: { + name: "Sequence", + element: { + type: { + name: "String" + } + } + } + }, + uncommitted: { + xmlName: "Uncommitted", + xmlElementName: "Uncommitted", + serializedName: "Uncommitted", + type: { + name: "Sequence", + element: { + type: { + name: "String" + } + } + } + }, + latest: { + xmlName: "Latest", + xmlElementName: "Latest", + serializedName: "Latest", + type: { + name: "Sequence", + element: { + type: { + name: "String" + } + } + } + } + } + } +}; + +export const ContainerProperties: msRest.CompositeMapper = { + serializedName: "ContainerProperties", + type: { + name: "Composite", + className: "ContainerProperties", + modelProperties: { + lastModified: { + xmlName: "Last-Modified", + required: true, + serializedName: "Last-Modified", + type: { + name: "DateTimeRfc1123" + } + }, + etag: { + xmlName: "Etag", + required: true, + serializedName: "Etag", + type: { + name: "String" + } + }, + leaseStatus: { + xmlName: "LeaseStatus", + serializedName: "LeaseStatus", + type: { + name: "Enum", + allowedValues: [ + "locked", + "unlocked" + ] + } + }, + leaseState: { + xmlName: "LeaseState", + serializedName: "LeaseState", + type: { + name: "Enum", + allowedValues: [ + "available", + "leased", + "expired", + "breaking", + "broken" + ] + } + }, + leaseDuration: { + xmlName: "LeaseDuration", + serializedName: "LeaseDuration", + type: { + name: "Enum", + allowedValues: [ + "infinite", + "fixed" + ] + } + }, + publicAccess: { + xmlName: "PublicAccess", + serializedName: "PublicAccess", + type: { + name: "String" + } + }, + hasImmutabilityPolicy: { + xmlName: "HasImmutabilityPolicy", + serializedName: "HasImmutabilityPolicy", + type: { + name: "Boolean" + } + }, + hasLegalHold: { + xmlName: "HasLegalHold", + serializedName: "HasLegalHold", + type: { + name: "Boolean" + } + }, + defaultEncryptionScope: { + xmlName: "DefaultEncryptionScope", + serializedName: "DefaultEncryptionScope", + type: { + name: "String" + } + }, + preventEncryptionScopeOverride: { + xmlName: "DenyEncryptionScopeOverride", + serializedName: "DenyEncryptionScopeOverride", + type: { + name: "Boolean" + } + }, + deletedTime: { + xmlName: "DeletedTime", + serializedName: "DeletedTime", + type: { + name: "DateTimeRfc1123" + } + }, + remainingRetentionDays: { + xmlName: "RemainingRetentionDays", + serializedName: "RemainingRetentionDays", + type: { + name: "Number" + } + }, + isImmutableStorageWithVersioningEnabled: { + xmlName: "ImmutableStorageWithVersioningEnabled", + serializedName: "ImmutableStorageWithVersioningEnabled", + type: { + name: "Boolean" + } + } + } + } +}; + +export const ContainerItem: msRest.CompositeMapper = { + xmlName: "Container", + serializedName: "ContainerItem", + type: { + name: "Composite", + className: "ContainerItem", + modelProperties: { + name: { + xmlName: "Name", + required: true, + serializedName: "Name", + type: { + name: "String" + } + }, + deleted: { + xmlName: "Deleted", + serializedName: "Deleted", + type: { + name: "Boolean" + } + }, + version: { + xmlName: "Version", + serializedName: "Version", + type: { + name: "String" + } + }, + properties: { + xmlName: "Properties", + required: true, + serializedName: "Properties", + type: { + name: "Composite", + className: "ContainerProperties" + } + }, + metadata: { + xmlName: "Metadata", + serializedName: "Metadata", + type: { + name: "Dictionary", + value: { + type: { + name: "String" + } + } + } + } + } + } +}; + +export const DelimitedTextConfiguration: msRest.CompositeMapper = { + serializedName: "DelimitedTextConfiguration", + type: { + name: "Composite", + className: "DelimitedTextConfiguration", + modelProperties: { + columnSeparator: { + xmlName: "ColumnSeparator", + serializedName: "ColumnSeparator", + type: { + name: "String" + } + }, + fieldQuote: { + xmlName: "FieldQuote", + serializedName: "FieldQuote", + type: { + name: "String" + } + }, + recordSeparator: { + xmlName: "RecordSeparator", + serializedName: "RecordSeparator", + type: { + name: "String" + } + }, + escapeChar: { + xmlName: "EscapeChar", + serializedName: "EscapeChar", + type: { + name: "String" + } + }, + headersPresent: { + xmlName: "HasHeaders", + serializedName: "HeadersPresent", + type: { + name: "Boolean" + } + } + } + } +}; + +export const JsonTextConfiguration: msRest.CompositeMapper = { + serializedName: "JsonTextConfiguration", + type: { + name: "Composite", + className: "JsonTextConfiguration", + modelProperties: { + recordSeparator: { + xmlName: "RecordSeparator", + serializedName: "RecordSeparator", + type: { + name: "String" + } + } + } + } +}; + +export const ArrowField: msRest.CompositeMapper = { + xmlName: "Field", + serializedName: "ArrowField", + type: { + name: "Composite", + className: "ArrowField", + modelProperties: { + type: { + xmlName: "Type", + required: true, + serializedName: "Type", + type: { + name: "String" + } + }, + name: { + xmlName: "Name", + serializedName: "Name", + type: { + name: "String" + } + }, + precision: { + xmlName: "Precision", + serializedName: "Precision", + type: { + name: "Number" + } + }, + scale: { + xmlName: "Scale", + serializedName: "Scale", + type: { + name: "Number" + } + } + } + } +}; + +export const ArrowConfiguration: msRest.CompositeMapper = { + serializedName: "ArrowConfiguration", + type: { + name: "Composite", + className: "ArrowConfiguration", + modelProperties: { + schema: { + xmlIsWrapped: true, + xmlName: "Schema", + xmlElementName: "Field", + required: true, + serializedName: "Schema", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "ArrowField" + } + } + } + } + } + } +}; + +export const ListContainersSegmentResponse: msRest.CompositeMapper = { + xmlName: "EnumerationResults", + serializedName: "ListContainersSegmentResponse", + type: { + name: "Composite", + className: "ListContainersSegmentResponse", + modelProperties: { + serviceEndpoint: { + xmlIsAttribute: true, + xmlName: "ServiceEndpoint", + required: true, + serializedName: "ServiceEndpoint", + type: { + name: "String" + } + }, + prefix: { + xmlName: "Prefix", + serializedName: "Prefix", + type: { + name: "String" + } + }, + marker: { + xmlName: "Marker", + serializedName: "Marker", + type: { + name: "String" + } + }, + maxResults: { + xmlName: "MaxResults", + serializedName: "MaxResults", + type: { + name: "Number" + } + }, + containerItems: { + xmlIsWrapped: true, + xmlName: "Containers", + xmlElementName: "Container", + required: true, + serializedName: "ContainerItems", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "ContainerItem" + } + } + } + }, + nextMarker: { + xmlName: "NextMarker", + serializedName: "NextMarker", + type: { + name: "String" + } + } + } + } +}; + +export const CorsRule: msRest.CompositeMapper = { + serializedName: "CorsRule", + type: { + name: "Composite", + className: "CorsRule", + modelProperties: { + allowedOrigins: { + xmlName: "AllowedOrigins", + required: true, + serializedName: "AllowedOrigins", + type: { + name: "String" + } + }, + allowedMethods: { + xmlName: "AllowedMethods", + required: true, + serializedName: "AllowedMethods", + type: { + name: "String" + } + }, + allowedHeaders: { + xmlName: "AllowedHeaders", + serializedName: "AllowedHeaders", + type: { + name: "String" + } + }, + exposedHeaders: { + xmlName: "ExposedHeaders", + serializedName: "ExposedHeaders", + type: { + name: "String" + } + }, + maxAgeInSeconds: { + xmlName: "MaxAgeInSeconds", + required: true, + serializedName: "MaxAgeInSeconds", + constraints: { + InclusiveMinimum: 0 + }, + type: { + name: "Number" + } + } + } + } +}; + +export const FilterBlobItem: msRest.CompositeMapper = { + xmlName: "Blob", + serializedName: "FilterBlobItem", + type: { + name: "Composite", + className: "FilterBlobItem", + modelProperties: { + name: { + xmlName: "Name", + required: true, + serializedName: "Name", + type: { + name: "String" + } + }, + containerName: { + xmlName: "ContainerName", + required: true, + serializedName: "ContainerName", + type: { + name: "String" + } + }, + tags: { + xmlName: "Tags", + serializedName: "Tags", + type: { + name: "Composite", + className: "BlobTags" + } + }, + versionId: { + xmlName: "VersionId", + serializedName: "VersionId", + type: { + name: "String" + } + }, + isCurrentVersion: { + xmlName: "IsCurrentVersion", + serializedName: "IsCurrentVersion", + type: { + name: "Boolean" + } + } + } + } +}; + +export const FilterBlobSegment: msRest.CompositeMapper = { + xmlName: "EnumerationResults", + serializedName: "FilterBlobSegment", + type: { + name: "Composite", + className: "FilterBlobSegment", + modelProperties: { + serviceEndpoint: { + xmlIsAttribute: true, + xmlName: "ServiceEndpoint", + required: true, + serializedName: "ServiceEndpoint", + type: { + name: "String" + } + }, + where: { + xmlName: "Where", + required: true, + serializedName: "Where", + type: { + name: "String" + } + }, + blobs: { + xmlIsWrapped: true, + xmlName: "Blobs", + xmlElementName: "Blob", + required: true, + serializedName: "Blobs", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "FilterBlobItem" + } + } + } + }, + nextMarker: { + xmlName: "NextMarker", + serializedName: "NextMarker", + type: { + name: "String" + } + } + } + } +}; + +export const GeoReplication: msRest.CompositeMapper = { + serializedName: "GeoReplication", + type: { + name: "Composite", + className: "GeoReplication", + modelProperties: { + status: { + xmlName: "Status", + required: true, + serializedName: "Status", + type: { + name: "String" + } + }, + lastSyncTime: { + xmlName: "LastSyncTime", + required: true, + serializedName: "LastSyncTime", + type: { + name: "DateTimeRfc1123" + } + } + } + } +}; + +export const RetentionPolicy: msRest.CompositeMapper = { + serializedName: "RetentionPolicy", + type: { + name: "Composite", + className: "RetentionPolicy", + modelProperties: { + enabled: { + xmlName: "Enabled", + required: true, + serializedName: "Enabled", + type: { + name: "Boolean" + } + }, + days: { + xmlName: "Days", + serializedName: "Days", + constraints: { + InclusiveMinimum: 1 + }, + type: { + name: "Number" + } + }, + allowPermanentDelete: { + xmlName: "AllowPermanentDelete", + serializedName: "AllowPermanentDelete", + type: { + name: "Boolean" + } + } + } + } +}; + +export const Logging: msRest.CompositeMapper = { + serializedName: "Logging", + type: { + name: "Composite", + className: "Logging", + modelProperties: { + version: { + xmlName: "Version", + required: true, + serializedName: "Version", + type: { + name: "String" + } + }, + deleteProperty: { + xmlName: "Delete", + required: true, + serializedName: "Delete", + type: { + name: "Boolean" + } + }, + read: { + xmlName: "Read", + required: true, + serializedName: "Read", + type: { + name: "Boolean" + } + }, + write: { + xmlName: "Write", + required: true, + serializedName: "Write", + type: { + name: "Boolean" + } + }, + retentionPolicy: { + xmlName: "RetentionPolicy", + required: true, + serializedName: "RetentionPolicy", + type: { + name: "Composite", + className: "RetentionPolicy" + } + } + } + } +}; + +export const Metrics: msRest.CompositeMapper = { + serializedName: "Metrics", + type: { + name: "Composite", + className: "Metrics", + modelProperties: { + version: { + xmlName: "Version", + serializedName: "Version", + type: { + name: "String" + } + }, + enabled: { + xmlName: "Enabled", + required: true, + serializedName: "Enabled", + type: { + name: "Boolean" + } + }, + includeAPIs: { + xmlName: "IncludeAPIs", + serializedName: "IncludeAPIs", + type: { + name: "Boolean" + } + }, + retentionPolicy: { + xmlName: "RetentionPolicy", + serializedName: "RetentionPolicy", + type: { + name: "Composite", + className: "RetentionPolicy" + } + } + } + } +}; + +export const PageRange: msRest.CompositeMapper = { + serializedName: "PageRange", + type: { + name: "Composite", + className: "PageRange", + modelProperties: { + start: { + xmlName: "Start", + required: true, + serializedName: "Start", + type: { + name: "Number" + } + }, + end: { + xmlName: "End", + required: true, + serializedName: "End", + type: { + name: "Number" + } + } + } + } +}; + +export const ClearRange: msRest.CompositeMapper = { + serializedName: "ClearRange", + type: { + name: "Composite", + className: "ClearRange", + modelProperties: { + start: { + xmlName: "Start", + required: true, + serializedName: "Start", + type: { + name: "Number" + } + }, + end: { + xmlName: "End", + required: true, + serializedName: "End", + type: { + name: "Number" + } + } + } + } +}; + +export const PageList: msRest.CompositeMapper = { + serializedName: "PageList", + type: { + name: "Composite", + className: "PageList", + modelProperties: { + pageRange: { + xmlName: "PageRange", + xmlElementName: "PageRange", + serializedName: "PageRange", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "PageRange" + } + } + } + }, + clearRange: { + xmlName: "ClearRange", + xmlElementName: "ClearRange", + serializedName: "ClearRange", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "ClearRange" + } + } + } + }, + nextMarker: { + xmlName: "NextMarker", + serializedName: "NextMarker", + type: { + name: "String" + } + } + } + } +}; + +export const QueryFormat: msRest.CompositeMapper = { + serializedName: "QueryFormat", + type: { + name: "Composite", + className: "QueryFormat", + modelProperties: { + type: { + xmlName: "Type", + required: true, + serializedName: "Type", + type: { + name: "Enum", + allowedValues: [ + "delimited", + "json", + "arrow", + "parquet" + ] + } + }, + delimitedTextConfiguration: { + xmlName: "DelimitedTextConfiguration", + serializedName: "DelimitedTextConfiguration", + type: { + name: "Composite", + className: "DelimitedTextConfiguration" + } + }, + jsonTextConfiguration: { + xmlName: "JsonTextConfiguration", + serializedName: "JsonTextConfiguration", + type: { + name: "Composite", + className: "JsonTextConfiguration" + } + }, + arrowConfiguration: { + xmlName: "ArrowConfiguration", + serializedName: "ArrowConfiguration", + type: { + name: "Composite", + className: "ArrowConfiguration" + } + }, + parquetTextConfiguration: { + xmlName: "ParquetTextConfiguration", + serializedName: "ParquetTextConfiguration", + type: { + name: "Object" + } + } + } + } +}; + +export const QuerySerialization: msRest.CompositeMapper = { + serializedName: "QuerySerialization", + type: { + name: "Composite", + className: "QuerySerialization", + modelProperties: { + format: { + xmlName: "Format", + required: true, + serializedName: "Format", + type: { + name: "Composite", + className: "QueryFormat" + } + } + } + } +}; + +export const QueryRequest: msRest.CompositeMapper = { + serializedName: "QueryRequest", + type: { + name: "Composite", + className: "QueryRequest", + modelProperties: { + queryType: { + xmlName: "QueryType", + required: true, + isConstant: true, + serializedName: "QueryType", + defaultValue: 'SQL', + type: { + name: "String" + } + }, + expression: { + xmlName: "Expression", + required: true, + serializedName: "Expression", + type: { + name: "String" + } + }, + inputSerialization: { + xmlName: "InputSerialization", + serializedName: "InputSerialization", + type: { + name: "Composite", + className: "QuerySerialization" + } + }, + outputSerialization: { + xmlName: "OutputSerialization", + serializedName: "OutputSerialization", + type: { + name: "Composite", + className: "QuerySerialization" + } + } + } + } +}; + +export const SignedIdentifier: msRest.CompositeMapper = { + serializedName: "SignedIdentifier", + type: { + name: "Composite", + className: "SignedIdentifier", + modelProperties: { + id: { + xmlName: "Id", + required: true, + serializedName: "Id", + type: { + name: "String" + } + }, + accessPolicy: { + xmlName: "AccessPolicy", + required: true, + serializedName: "AccessPolicy", + type: { + name: "Composite", + className: "AccessPolicy" + } + } + } + } +}; + +export const StaticWebsite: msRest.CompositeMapper = { + serializedName: "StaticWebsite", + type: { + name: "Composite", + className: "StaticWebsite", + modelProperties: { + enabled: { + xmlName: "Enabled", + required: true, + serializedName: "Enabled", + type: { + name: "Boolean" + } + }, + indexDocument: { + xmlName: "IndexDocument", + serializedName: "IndexDocument", + type: { + name: "String" + } + }, + errorDocument404Path: { + xmlName: "ErrorDocument404Path", + serializedName: "ErrorDocument404Path", + type: { + name: "String" + } + }, + defaultIndexDocumentPath: { + xmlName: "DefaultIndexDocumentPath", + serializedName: "DefaultIndexDocumentPath", + type: { + name: "String" + } + } + } + } +}; + +export const StorageServiceProperties: msRest.CompositeMapper = { + serializedName: "StorageServiceProperties", + type: { + name: "Composite", + className: "StorageServiceProperties", + modelProperties: { + logging: { + xmlName: "Logging", + serializedName: "Logging", + type: { + name: "Composite", + className: "Logging" + } + }, + hourMetrics: { + xmlName: "HourMetrics", + serializedName: "HourMetrics", + type: { + name: "Composite", + className: "Metrics" + } + }, + minuteMetrics: { + xmlName: "MinuteMetrics", + serializedName: "MinuteMetrics", + type: { + name: "Composite", + className: "Metrics" + } + }, + cors: { + xmlIsWrapped: true, + xmlName: "Cors", + xmlElementName: "CorsRule", + serializedName: "Cors", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "CorsRule" + } + } + } + }, + defaultServiceVersion: { + xmlName: "DefaultServiceVersion", + serializedName: "DefaultServiceVersion", + type: { + name: "String" + } + }, + deleteRetentionPolicy: { + xmlName: "DeleteRetentionPolicy", + serializedName: "DeleteRetentionPolicy", + type: { + name: "Composite", + className: "RetentionPolicy" + } + }, + staticWebsite: { + xmlName: "StaticWebsite", + serializedName: "StaticWebsite", + type: { + name: "Composite", + className: "StaticWebsite" + } + } + } + } +}; + +export const StorageServiceStats: msRest.CompositeMapper = { + serializedName: "StorageServiceStats", + type: { + name: "Composite", + className: "StorageServiceStats", + modelProperties: { + geoReplication: { + xmlName: "GeoReplication", + serializedName: "GeoReplication", + type: { + name: "Composite", + className: "GeoReplication" + } + } + } + } +}; + +export const ModifiedAccessConditions: msRest.CompositeMapper = { + xmlName: "modified-access-conditions", + type: { + name: "Composite", + className: "ModifiedAccessConditions", + modelProperties: { + ifModifiedSince: { + xmlName: "ifModifiedSince", + type: { + name: "DateTimeRfc1123" + } + }, + ifUnmodifiedSince: { + xmlName: "ifUnmodifiedSince", + type: { + name: "DateTimeRfc1123" + } + }, + ifMatch: { + xmlName: "ifMatch", + type: { + name: "String" + } + }, + ifNoneMatch: { + xmlName: "ifNoneMatch", + type: { + name: "String" + } + }, + ifTags: { + xmlName: "ifTags", + type: { + name: "String" + } + } + } + } +}; + +export const PathHTTPHeaders: msRest.CompositeMapper = { + xmlName: "path-HTTP-headers", + type: { + name: "Composite", + className: "PathHTTPHeaders", + modelProperties: { + cacheControl: { + xmlName: "cacheControl", + type: { + name: "String" + } + }, + contentEncoding: { + xmlName: "contentEncoding", + type: { + name: "String" + } + }, + contentLanguage: { + xmlName: "contentLanguage", + type: { + name: "String" + } + }, + contentDisposition: { + xmlName: "contentDisposition", + type: { + name: "String" + } + }, + contentType: { + xmlName: "contentType", + type: { + name: "String" + } + }, + contentMD5: { + xmlName: "contentMD5", + type: { + name: "ByteArray" + } + }, + transactionalContentHash: { + xmlName: "transactionalContentHash", + type: { + name: "ByteArray" + } + } + } + } +}; + +export const LeaseAccessConditions: msRest.CompositeMapper = { + xmlName: "lease-access-conditions", + type: { + name: "Composite", + className: "LeaseAccessConditions", + modelProperties: { + leaseId: { + xmlName: "leaseId", + type: { + name: "String" + } + } + } + } +}; + +export const SourceModifiedAccessConditions: msRest.CompositeMapper = { + xmlName: "source-modified-access-conditions", + type: { + name: "Composite", + className: "SourceModifiedAccessConditions", + modelProperties: { + sourceIfMatch: { + xmlName: "sourceIfMatch", + type: { + name: "String" + } + }, + sourceIfNoneMatch: { + xmlName: "sourceIfNoneMatch", + type: { + name: "String" + } + }, + sourceIfModifiedSince: { + xmlName: "sourceIfModifiedSince", + type: { + name: "DateTimeRfc1123" + } + }, + sourceIfUnmodifiedSince: { + xmlName: "sourceIfUnmodifiedSince", + type: { + name: "DateTimeRfc1123" + } + }, + sourceIfTags: { + xmlName: "sourceIfTags", + type: { + name: "String" + } + } + } + } +}; + +export const CpkInfo: msRest.CompositeMapper = { + xmlName: "cpk-info", + type: { + name: "Composite", + className: "CpkInfo", + modelProperties: { + encryptionKey: { + xmlName: "encryptionKey", + type: { + name: "String" + } + }, + encryptionKeySha256: { + xmlName: "encryptionKeySha256", + type: { + name: "String" + } + }, + encryptionAlgorithm: { + xmlName: "encryptionAlgorithm", + type: { + name: "Enum", + allowedValues: [ + "AES256" + ] + } + } + } + } +}; + +export const ContainerCpkScopeInfo: msRest.CompositeMapper = { + xmlName: "container-cpk-scope-info", + type: { + name: "Composite", + className: "ContainerCpkScopeInfo", + modelProperties: { + defaultEncryptionScope: { + xmlName: "defaultEncryptionScope", + type: { + name: "String" + } + }, + preventEncryptionScopeOverride: { + xmlName: "preventEncryptionScopeOverride", + type: { + name: "Boolean" + } + } + } + } +}; + +export const BlobHTTPHeaders: msRest.CompositeMapper = { + xmlName: "blob-HTTP-headers", + type: { + name: "Composite", + className: "BlobHTTPHeaders", + modelProperties: { + blobContentType: { + xmlName: "blobContentType", + type: { + name: "String" + } + }, + blobContentEncoding: { + xmlName: "blobContentEncoding", + type: { + name: "String" + } + }, + blobContentLanguage: { + xmlName: "blobContentLanguage", + type: { + name: "String" + } + }, + blobContentMD5: { + xmlName: "blobContentMD5", + type: { + name: "ByteArray" + } + }, + blobCacheControl: { + xmlName: "blobCacheControl", + type: { + name: "String" + } + }, + blobContentDisposition: { + xmlName: "blobContentDisposition", + type: { + name: "String" + } + } + } + } +}; + +export const CpkScopeInfo: msRest.CompositeMapper = { + xmlName: "cpk-scope-info", + type: { + name: "Composite", + className: "CpkScopeInfo", + modelProperties: { + encryptionScope: { + xmlName: "encryptionScope", + type: { + name: "String" + } + } + } + } +}; + +export const SequenceNumberAccessConditions: msRest.CompositeMapper = { + xmlName: "sequence-number-access-conditions", + type: { + name: "Composite", + className: "SequenceNumberAccessConditions", + modelProperties: { + ifSequenceNumberLessThanOrEqualTo: { + xmlName: "ifSequenceNumberLessThanOrEqualTo", + type: { + name: "Number" + } + }, + ifSequenceNumberLessThan: { + xmlName: "ifSequenceNumberLessThan", + type: { + name: "Number" + } + }, + ifSequenceNumberEqualTo: { + xmlName: "ifSequenceNumberEqualTo", + type: { + name: "Number" + } + } + } + } +}; + +export const AppendPositionAccessConditions: msRest.CompositeMapper = { + xmlName: "append-position-access-conditions", + type: { + name: "Composite", + className: "AppendPositionAccessConditions", + modelProperties: { + maxSize: { + xmlName: "maxSize", + type: { + name: "Number" + } + }, + appendPosition: { + xmlName: "appendPosition", + type: { + name: "Number" + } + } + } + } +}; + +export const ServiceListFileSystemsHeaders: msRest.CompositeMapper = { + serializedName: "service-listfilesystems-headers", + type: { + name: "Composite", + className: "ServiceListFileSystemsHeaders", + modelProperties: { + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + continuation: { + serializedName: "x-ms-continuation", + type: { + name: "String" + } + }, + contentType: { + serializedName: "content-type", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const FileSystemCreateHeaders: msRest.CompositeMapper = { + serializedName: "filesystem-create-headers", + type: { + name: "Composite", + className: "FileSystemCreateHeaders", + modelProperties: { + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + clientRequestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + namespaceEnabled: { + serializedName: "x-ms-namespace-enabled", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const FileSystemSetPropertiesHeaders: msRest.CompositeMapper = { + serializedName: "filesystem-setproperties-headers", + type: { + name: "Composite", + className: "FileSystemSetPropertiesHeaders", + modelProperties: { + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const FileSystemGetPropertiesHeaders: msRest.CompositeMapper = { + serializedName: "filesystem-getproperties-headers", + type: { + name: "Composite", + className: "FileSystemGetPropertiesHeaders", + modelProperties: { + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + properties: { + serializedName: "x-ms-properties", + type: { + name: "String" + } + }, + namespaceEnabled: { + serializedName: "x-ms-namespace-enabled", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const FileSystemDeleteHeaders: msRest.CompositeMapper = { + serializedName: "filesystem-delete-headers", + type: { + name: "Composite", + className: "FileSystemDeleteHeaders", + modelProperties: { + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const FileSystemListPathsHeaders: msRest.CompositeMapper = { + serializedName: "filesystem-listpaths-headers", + type: { + name: "Composite", + className: "FileSystemListPathsHeaders", + modelProperties: { + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + continuation: { + serializedName: "x-ms-continuation", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const FileSystemListBlobFlatSegmentHeaders: msRest.CompositeMapper = { + serializedName: "filesystem-listblobflatsegment-headers", + type: { + name: "Composite", + className: "FileSystemListBlobFlatSegmentHeaders", + modelProperties: { + contentType: { + serializedName: "content-type", + type: { + name: "String" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const FileSystemListBlobHierarchySegmentHeaders: msRest.CompositeMapper = { + serializedName: "filesystem-listblobhierarchysegment-headers", + type: { + name: "Composite", + className: "FileSystemListBlobHierarchySegmentHeaders", + modelProperties: { + contentType: { + serializedName: "content-type", + type: { + name: "String" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const PathCreateHeaders: msRest.CompositeMapper = { + serializedName: "path-create-headers", + type: { + name: "Composite", + className: "PathCreateHeaders", + modelProperties: { + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + continuation: { + serializedName: "x-ms-continuation", + type: { + name: "String" + } + }, + contentLength: { + serializedName: "content-length", + type: { + name: "Number" + } + }, + isServerEncrypted: { + serializedName: "x-ms-request-server-encrypted", + type: { + name: "Boolean" + } + }, + encryptionKeySha256: { + serializedName: "x-ms-encryption-key-sha256", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const PathUpdateHeaders: msRest.CompositeMapper = { + serializedName: "path-update-headers", + type: { + name: "Composite", + className: "PathUpdateHeaders", + modelProperties: { + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + acceptRanges: { + serializedName: "accept-ranges", + type: { + name: "String" + } + }, + cacheControl: { + serializedName: "cache-control", + type: { + name: "String" + } + }, + contentDisposition: { + serializedName: "content-disposition", + type: { + name: "String" + } + }, + contentEncoding: { + serializedName: "content-encoding", + type: { + name: "String" + } + }, + contentLanguage: { + serializedName: "content-language", + type: { + name: "String" + } + }, + contentLength: { + serializedName: "content-length", + type: { + name: "Number" + } + }, + contentRange: { + serializedName: "content-range", + type: { + name: "String" + } + }, + contentType: { + serializedName: "content-type", + type: { + name: "String" + } + }, + contentMD5: { + serializedName: "content-md5", + type: { + name: "ByteArray" + } + }, + properties: { + serializedName: "x-ms-properties", + type: { + name: "String" + } + }, + xMsContinuation: { + serializedName: "x-ms-continuation", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const PathLeaseHeaders: msRest.CompositeMapper = { + serializedName: "path-lease-headers", + type: { + name: "Composite", + className: "PathLeaseHeaders", + modelProperties: { + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + leaseId: { + serializedName: "x-ms-lease-id", + type: { + name: "String" + } + }, + leaseTime: { + serializedName: "x-ms-lease-time", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const PathReadHeaders: msRest.CompositeMapper = { + serializedName: "path-read-headers", + type: { + name: "Composite", + className: "PathReadHeaders", + modelProperties: { + acceptRanges: { + serializedName: "accept-ranges", + type: { + name: "String" + } + }, + cacheControl: { + serializedName: "cache-control", + type: { + name: "String" + } + }, + contentDisposition: { + serializedName: "content-disposition", + type: { + name: "String" + } + }, + contentEncoding: { + serializedName: "content-encoding", + type: { + name: "String" + } + }, + contentLanguage: { + serializedName: "content-language", + type: { + name: "String" + } + }, + contentLength: { + serializedName: "content-length", + type: { + name: "Number" + } + }, + contentRange: { + serializedName: "content-range", + type: { + name: "String" + } + }, + contentType: { + serializedName: "content-type", + type: { + name: "String" + } + }, + contentMD5: { + serializedName: "content-md5", + type: { + name: "ByteArray" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + resourceType: { + serializedName: "x-ms-resource-type", + type: { + name: "String" + } + }, + properties: { + serializedName: "x-ms-properties", + type: { + name: "String" + } + }, + leaseDuration: { + serializedName: "x-ms-lease-duration", + type: { + name: "Enum", + allowedValues: [ + "infinite", + "fixed" + ] + } + }, + leaseState: { + serializedName: "x-ms-lease-state", + type: { + name: "Enum", + allowedValues: [ + "available", + "leased", + "expired", + "breaking", + "broken" + ] + } + }, + leaseStatus: { + serializedName: "x-ms-lease-status", + type: { + name: "Enum", + allowedValues: [ + "locked", + "unlocked" + ] + } + }, + isServerEncrypted: { + serializedName: "x-ms-request-server-encrypted", + type: { + name: "Boolean" + } + }, + encryptionKeySha256: { + serializedName: "x-ms-encryption-key-sha256", + type: { + name: "String" + } + }, + metadata: { + serializedName: "x-ms-meta", + type: { + name: "Dictionary", + value: { + type: { + name: "String" + } + } + }, + headerCollectionPrefix: "x-ms-meta-" + }, + creationTime: { + serializedName: "x-ms-creation-time", + type: { + name: "DateTimeRfc1123" + } + }, + objectReplicationPolicyId: { + serializedName: "x-ms-or-policy-id", + type: { + name: "String" + } + }, + objectReplicationRules: { + serializedName: "x-ms-or", + type: { + name: "Dictionary", + value: { + type: { + name: "String" + } + } + }, + headerCollectionPrefix: "x-ms-or-" + }, + blobSequenceNumber: { + serializedName: "x-ms-blob-sequence-number", + type: { + name: "Number" + } + }, + blobType: { + serializedName: "x-ms-blob-type", + type: { + name: "Enum", + allowedValues: [ + "BlockBlob", + "PageBlob", + "AppendBlob" + ] + } + }, + copyCompletionTime: { + serializedName: "x-ms-copy-completion-time", + type: { + name: "DateTimeRfc1123" + } + }, + copyStatusDescription: { + serializedName: "x-ms-copy-status-description", + type: { + name: "String" + } + }, + copyId: { + serializedName: "x-ms-copy-id", + type: { + name: "String" + } + }, + copyProgress: { + serializedName: "x-ms-copy-progress", + type: { + name: "String" + } + }, + copySource: { + serializedName: "x-ms-copy-source", + type: { + name: "String" + } + }, + copyStatus: { + serializedName: "x-ms-copy-status", + type: { + name: "Enum", + allowedValues: [ + "pending", + "success", + "aborted", + "failed" + ] + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + versionId: { + serializedName: "x-ms-version-id", + type: { + name: "String" + } + }, + isCurrentVersion: { + serializedName: "x-ms-is-current-version", + type: { + name: "Boolean" + } + }, + blobCommittedBlockCount: { + serializedName: "x-ms-blob-committed-block-count", + type: { + name: "Number" + } + }, + encryptionScope: { + serializedName: "x-ms-encryption-scope", + type: { + name: "String" + } + }, + blobContentMD5: { + serializedName: "x-ms-blob-content-md5", + type: { + name: "ByteArray" + } + }, + tagCount: { + serializedName: "x-ms-tag-count", + type: { + name: "Number" + } + }, + isSealed: { + serializedName: "x-ms-blob-sealed", + type: { + name: "Boolean" + } + }, + lastAccessed: { + serializedName: "x-ms-last-access-time", + type: { + name: "DateTimeRfc1123" + } + }, + immutabilityPolicyExpiresOn: { + serializedName: "x-ms-immutability-policy-until-date", + type: { + name: "DateTimeRfc1123" + } + }, + immutabilityPolicyMode: { + serializedName: "x-ms-immutability-policy-mode", + type: { + name: "String" + } + }, + legalHold: { + serializedName: "x-ms-legal-hold", + type: { + name: "Boolean" + } + }, + xMsContentMd5: { + serializedName: "x-ms-content-md5", + type: { + name: "ByteArray" + } + }, + contentCrc64: { + serializedName: "x-ms-content-crc64", + type: { + name: "ByteArray" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const PathGetPropertiesHeaders: msRest.CompositeMapper = { + serializedName: "path-getproperties-headers", + type: { + name: "Composite", + className: "PathGetPropertiesHeaders", + modelProperties: { + acceptRanges: { + serializedName: "accept-ranges", + type: { + name: "String" + } + }, + cacheControl: { + serializedName: "cache-control", + type: { + name: "String" + } + }, + contentDisposition: { + serializedName: "content-disposition", + type: { + name: "String" + } + }, + contentEncoding: { + serializedName: "content-encoding", + type: { + name: "String" + } + }, + contentLanguage: { + serializedName: "content-language", + type: { + name: "String" + } + }, + contentLength: { + serializedName: "content-length", + type: { + name: "Number" + } + }, + contentRange: { + serializedName: "content-range", + type: { + name: "String" + } + }, + contentType: { + serializedName: "content-type", + type: { + name: "String" + } + }, + contentMD5: { + serializedName: "content-md5", + type: { + name: "ByteArray" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + resourceType: { + serializedName: "x-ms-resource-type", + type: { + name: "String" + } + }, + properties: { + serializedName: "x-ms-properties", + type: { + name: "String" + } + }, + owner: { + serializedName: "x-ms-owner", + type: { + name: "String" + } + }, + group: { + serializedName: "x-ms-group", + type: { + name: "String" + } + }, + permissions: { + serializedName: "x-ms-permissions", + type: { + name: "String" + } + }, + aCL: { + serializedName: "x-ms-acl", + type: { + name: "String" + } + }, + leaseDuration: { + serializedName: "x-ms-lease-duration", + type: { + name: "Enum", + allowedValues: [ + "infinite", + "fixed" + ] + } + }, + leaseState: { + serializedName: "x-ms-lease-state", + type: { + name: "Enum", + allowedValues: [ + "available", + "leased", + "expired", + "breaking", + "broken" + ] + } + }, + leaseStatus: { + serializedName: "x-ms-lease-status", + type: { + name: "Enum", + allowedValues: [ + "locked", + "unlocked" + ] + } + }, + metadata: { + serializedName: "x-ms-meta", + type: { + name: "Dictionary", + value: { + type: { + name: "String" + } + } + }, + headerCollectionPrefix: "x-ms-meta-" + }, + creationTime: { + serializedName: "x-ms-creation-time", + type: { + name: "DateTimeRfc1123" + } + }, + objectReplicationPolicyId: { + serializedName: "x-ms-or-policy-id", + type: { + name: "String" + } + }, + objectReplicationRules: { + serializedName: "x-ms-or", + type: { + name: "Dictionary", + value: { + type: { + name: "String" + } + } + }, + headerCollectionPrefix: "x-ms-or-" + }, + blobType: { + serializedName: "x-ms-blob-type", + type: { + name: "Enum", + allowedValues: [ + "BlockBlob", + "PageBlob", + "AppendBlob" + ] + } + }, + copyCompletionTime: { + serializedName: "x-ms-copy-completion-time", + type: { + name: "DateTimeRfc1123" + } + }, + copyStatusDescription: { + serializedName: "x-ms-copy-status-description", + type: { + name: "String" + } + }, + copyId: { + serializedName: "x-ms-copy-id", + type: { + name: "String" + } + }, + copyProgress: { + serializedName: "x-ms-copy-progress", + type: { + name: "String" + } + }, + copySource: { + serializedName: "x-ms-copy-source", + type: { + name: "String" + } + }, + copyStatus: { + serializedName: "x-ms-copy-status", + type: { + name: "Enum", + allowedValues: [ + "pending", + "success", + "aborted", + "failed" + ] + } + }, + isIncrementalCopy: { + serializedName: "x-ms-incremental-copy", + type: { + name: "Boolean" + } + }, + destinationSnapshot: { + serializedName: "x-ms-copy-destination-snapshot", + type: { + name: "String" + } + }, + blobSequenceNumber: { + serializedName: "x-ms-blob-sequence-number", + type: { + name: "Number" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + blobCommittedBlockCount: { + serializedName: "x-ms-blob-committed-block-count", + type: { + name: "Number" + } + }, + isServerEncrypted: { + serializedName: "x-ms-server-encrypted", + type: { + name: "Boolean" + } + }, + encryptionKeySha256: { + serializedName: "x-ms-encryption-key-sha256", + type: { + name: "String" + } + }, + encryptionScope: { + serializedName: "x-ms-encryption-scope", + type: { + name: "String" + } + }, + accessTier: { + serializedName: "x-ms-access-tier", + type: { + name: "String" + } + }, + accessTierInferred: { + serializedName: "x-ms-access-tier-inferred", + type: { + name: "Boolean" + } + }, + archiveStatus: { + serializedName: "x-ms-archive-status", + type: { + name: "String" + } + }, + accessTierChangeTime: { + serializedName: "x-ms-access-tier-change-time", + type: { + name: "DateTimeRfc1123" + } + }, + versionId: { + serializedName: "x-ms-version-id", + type: { + name: "String" + } + }, + isCurrentVersion: { + serializedName: "x-ms-is-current-version", + type: { + name: "Boolean" + } + }, + tagCount: { + serializedName: "x-ms-tag-count", + type: { + name: "Number" + } + }, + expiresOn: { + serializedName: "x-ms-expiry-time", + type: { + name: "DateTimeRfc1123" + } + }, + isSealed: { + serializedName: "x-ms-blob-sealed", + type: { + name: "Boolean" + } + }, + rehydratePriority: { + serializedName: "x-ms-rehydrate-priority", + type: { + name: "String" + } + }, + lastAccessed: { + serializedName: "x-ms-last-access-time", + type: { + name: "DateTimeRfc1123" + } + }, + immutabilityPolicyExpiresOn: { + serializedName: "x-ms-immutability-policy-until-date", + type: { + name: "DateTimeRfc1123" + } + }, + immutabilityPolicyMode: { + serializedName: "x-ms-immutability-policy-mode", + type: { + name: "Enum", + allowedValues: [ + "Mutable", + "Unlocked", + "Locked" + ] + } + }, + legalHold: { + serializedName: "x-ms-legal-hold", + type: { + name: "Boolean" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const PathDeleteHeaders: msRest.CompositeMapper = { + serializedName: "path-delete-headers", + type: { + name: "Composite", + className: "PathDeleteHeaders", + modelProperties: { + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + continuation: { + serializedName: "x-ms-continuation", + type: { + name: "String" + } + }, + deletionId: { + serializedName: "x-ms-deletion-id", + type: { + name: "String" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const PathSetAccessControlHeaders: msRest.CompositeMapper = { + serializedName: "path-setaccesscontrol-headers", + type: { + name: "Composite", + className: "PathSetAccessControlHeaders", + modelProperties: { + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + } + } + } +}; + +export const PathSetAccessControlRecursiveHeaders: msRest.CompositeMapper = { + serializedName: "path-setaccesscontrolrecursive-headers", + type: { + name: "Composite", + className: "PathSetAccessControlRecursiveHeaders", + modelProperties: { + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + continuation: { + serializedName: "x-ms-continuation", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + } + } + } +}; + +export const PathSetPropertiesHeaders: msRest.CompositeMapper = { + serializedName: "path-setproperties-headers", + type: { + name: "Composite", + className: "PathSetPropertiesHeaders", + modelProperties: { + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + cacheControl: { + serializedName: "cache-control", + type: { + name: "String" + } + }, + contentDisposition: { + serializedName: "content-disposition", + type: { + name: "String" + } + }, + contentEncoding: { + serializedName: "content-encoding", + type: { + name: "String" + } + }, + contentLanguage: { + serializedName: "content-language", + type: { + name: "String" + } + }, + contentLength: { + serializedName: "content-length", + type: { + name: "Number" + } + }, + contentType: { + serializedName: "content-type", + type: { + name: "String" + } + }, + contentMD5: { + serializedName: "content-md5", + type: { + name: "ByteArray" + } + }, + properties: { + serializedName: "x-ms-properties", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + } + } + } +}; + +export const PathFlushDataHeaders: msRest.CompositeMapper = { + serializedName: "path-flushdata-headers", + type: { + name: "Composite", + className: "PathFlushDataHeaders", + modelProperties: { + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + contentLength: { + serializedName: "content-length", + type: { + name: "Number" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + isServerEncrypted: { + serializedName: "x-ms-request-server-encrypted", + type: { + name: "Boolean" + } + }, + encryptionKeySha256: { + serializedName: "x-ms-encryption-key-sha256", + type: { + name: "String" + } + } + } + } +}; + +export const PathAppendDataHeaders: msRest.CompositeMapper = { + serializedName: "path-appenddata-headers", + type: { + name: "Composite", + className: "PathAppendDataHeaders", + modelProperties: { + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + contentMD5: { + serializedName: "content-md5", + type: { + name: "ByteArray" + } + }, + xMsContentCrc64: { + serializedName: "x-ms-content-crc64", + type: { + name: "ByteArray" + } + }, + isServerEncrypted: { + serializedName: "x-ms-request-server-encrypted", + type: { + name: "Boolean" + } + }, + encryptionKeySha256: { + serializedName: "x-ms-encryption-key-sha256", + type: { + name: "String" + } + } + } + } +}; + +export const PathSetExpiryHeaders: msRest.CompositeMapper = { + serializedName: "path-setexpiry-headers", + type: { + name: "Composite", + className: "PathSetExpiryHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const PathUndeleteHeaders: msRest.CompositeMapper = { + serializedName: "path-undelete-headers", + type: { + name: "Composite", + className: "PathUndeleteHeaders", + modelProperties: { + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + resourceType: { + serializedName: "x-ms-resource-type", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ServiceSetPropertiesHeaders: msRest.CompositeMapper = { + serializedName: "service-setproperties-headers", + type: { + name: "Composite", + className: "ServiceSetPropertiesHeaders", + modelProperties: { + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ServiceGetPropertiesHeaders: msRest.CompositeMapper = { + serializedName: "service-getproperties-headers", + type: { + name: "Composite", + className: "ServiceGetPropertiesHeaders", + modelProperties: { + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ServiceGetStatisticsHeaders: msRest.CompositeMapper = { + serializedName: "service-getstatistics-headers", + type: { + name: "Composite", + className: "ServiceGetStatisticsHeaders", + modelProperties: { + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ServiceListContainersSegmentHeaders: msRest.CompositeMapper = { + serializedName: "service-listcontainerssegment-headers", + type: { + name: "Composite", + className: "ServiceListContainersSegmentHeaders", + modelProperties: { + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ServiceGetUserDelegationKeyHeaders: msRest.CompositeMapper = { + serializedName: "service-getuserdelegationkey-headers", + type: { + name: "Composite", + className: "ServiceGetUserDelegationKeyHeaders", + modelProperties: { + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ServiceGetAccountInfoHeaders: msRest.CompositeMapper = { + serializedName: "service-getaccountinfo-headers", + type: { + name: "Composite", + className: "ServiceGetAccountInfoHeaders", + modelProperties: { + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + skuName: { + serializedName: "x-ms-sku-name", + type: { + name: "Enum", + allowedValues: [ + "Standard_LRS", + "Standard_GRS", + "Standard_RAGRS", + "Standard_ZRS", + "Premium_LRS" + ] + } + }, + accountKind: { + serializedName: "x-ms-account-kind", + type: { + name: "Enum", + allowedValues: [ + "Storage", + "BlobStorage", + "StorageV2", + "FileStorage", + "BlockBlobStorage" + ] + } + }, + isHierarchicalNamespaceEnabled: { + serializedName: "x-ms-is-hns-enabled", + type: { + name: "Boolean" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ServiceGetAccountInfoWithHeadHeaders: msRest.CompositeMapper = { + serializedName: "service-getaccountinfowithhead-headers", + type: { + name: "Composite", + className: "ServiceGetAccountInfoWithHeadHeaders", + modelProperties: { + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + skuName: { + serializedName: "x-ms-sku-name", + type: { + name: "Enum", + allowedValues: [ + "Standard_LRS", + "Standard_GRS", + "Standard_RAGRS", + "Standard_ZRS", + "Premium_LRS" + ] + } + }, + accountKind: { + serializedName: "x-ms-account-kind", + type: { + name: "Enum", + allowedValues: [ + "Storage", + "BlobStorage", + "StorageV2", + "FileStorage", + "BlockBlobStorage" + ] + } + }, + isHierarchicalNamespaceEnabled: { + serializedName: "x-ms-is-hns-enabled", + type: { + name: "Boolean" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ServiceSubmitBatchHeaders: msRest.CompositeMapper = { + serializedName: "service-submitbatch-headers", + type: { + name: "Composite", + className: "ServiceSubmitBatchHeaders", + modelProperties: { + contentType: { + serializedName: "content-type", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ServiceFilterBlobsHeaders: msRest.CompositeMapper = { + serializedName: "service-filterblobs-headers", + type: { + name: "Composite", + className: "ServiceFilterBlobsHeaders", + modelProperties: { + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ContainerCreateHeaders: msRest.CompositeMapper = { + serializedName: "container-create-headers", + type: { + name: "Composite", + className: "ContainerCreateHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ContainerGetPropertiesHeaders: msRest.CompositeMapper = { + serializedName: "container-getproperties-headers", + type: { + name: "Composite", + className: "ContainerGetPropertiesHeaders", + modelProperties: { + metadata: { + serializedName: "x-ms-meta", + type: { + name: "Dictionary", + value: { + type: { + name: "String" + } + } + }, + headerCollectionPrefix: "x-ms-meta-" + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + leaseDuration: { + serializedName: "x-ms-lease-duration", + type: { + name: "Enum", + allowedValues: [ + "infinite", + "fixed" + ] + } + }, + leaseState: { + serializedName: "x-ms-lease-state", + type: { + name: "Enum", + allowedValues: [ + "available", + "leased", + "expired", + "breaking", + "broken" + ] + } + }, + leaseStatus: { + serializedName: "x-ms-lease-status", + type: { + name: "Enum", + allowedValues: [ + "locked", + "unlocked" + ] + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + blobPublicAccess: { + serializedName: "x-ms-blob-public-access", + type: { + name: "String" + } + }, + hasImmutabilityPolicy: { + serializedName: "x-ms-has-immutability-policy", + type: { + name: "Boolean" + } + }, + hasLegalHold: { + serializedName: "x-ms-has-legal-hold", + type: { + name: "Boolean" + } + }, + defaultEncryptionScope: { + serializedName: "x-ms-default-encryption-scope", + type: { + name: "String" + } + }, + denyEncryptionScopeOverride: { + serializedName: "x-ms-deny-encryption-scope-override", + type: { + name: "Boolean" + } + }, + isImmutableStorageWithVersioningEnabled: { + serializedName: "x-ms-immutable-storage-with-versioning-enabled", + type: { + name: "Boolean" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ContainerGetPropertiesWithHeadHeaders: msRest.CompositeMapper = { + serializedName: "container-getpropertieswithhead-headers", + type: { + name: "Composite", + className: "ContainerGetPropertiesWithHeadHeaders", + modelProperties: { + metadata: { + serializedName: "x-ms-meta", + type: { + name: "Dictionary", + value: { + type: { + name: "String" + } + } + }, + headerCollectionPrefix: "x-ms-meta-" + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + leaseDuration: { + serializedName: "x-ms-lease-duration", + type: { + name: "Enum", + allowedValues: [ + "infinite", + "fixed" + ] + } + }, + leaseState: { + serializedName: "x-ms-lease-state", + type: { + name: "Enum", + allowedValues: [ + "available", + "leased", + "expired", + "breaking", + "broken" + ] + } + }, + leaseStatus: { + serializedName: "x-ms-lease-status", + type: { + name: "Enum", + allowedValues: [ + "locked", + "unlocked" + ] + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + blobPublicAccess: { + serializedName: "x-ms-blob-public-access", + type: { + name: "String" + } + }, + hasImmutabilityPolicy: { + serializedName: "x-ms-has-immutability-policy", + type: { + name: "Boolean" + } + }, + hasLegalHold: { + serializedName: "x-ms-has-legal-hold", + type: { + name: "Boolean" + } + }, + defaultEncryptionScope: { + serializedName: "x-ms-default-encryption-scope", + type: { + name: "String" + } + }, + denyEncryptionScopeOverride: { + serializedName: "x-ms-deny-encryption-scope-override", + type: { + name: "Boolean" + } + }, + isImmutableStorageWithVersioningEnabled: { + serializedName: "x-ms-immutable-storage-with-versioning-enabled", + type: { + name: "Boolean" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ContainerDeleteHeaders: msRest.CompositeMapper = { + serializedName: "container-delete-headers", + type: { + name: "Composite", + className: "ContainerDeleteHeaders", + modelProperties: { + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ContainerSetMetadataHeaders: msRest.CompositeMapper = { + serializedName: "container-setmetadata-headers", + type: { + name: "Composite", + className: "ContainerSetMetadataHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ContainerGetAccessPolicyHeaders: msRest.CompositeMapper = { + serializedName: "container-getaccesspolicy-headers", + type: { + name: "Composite", + className: "ContainerGetAccessPolicyHeaders", + modelProperties: { + blobPublicAccess: { + serializedName: "x-ms-blob-public-access", + type: { + name: "String" + } + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ContainerSetAccessPolicyHeaders: msRest.CompositeMapper = { + serializedName: "container-setaccesspolicy-headers", + type: { + name: "Composite", + className: "ContainerSetAccessPolicyHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ContainerRestoreHeaders: msRest.CompositeMapper = { + serializedName: "container-restore-headers", + type: { + name: "Composite", + className: "ContainerRestoreHeaders", + modelProperties: { + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ContainerSubmitBatchHeaders: msRest.CompositeMapper = { + serializedName: "container-submitbatch-headers", + type: { + name: "Composite", + className: "ContainerSubmitBatchHeaders", + modelProperties: { + contentType: { + serializedName: "content-type", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ContainerFilterBlobsHeaders: msRest.CompositeMapper = { + serializedName: "container-filterblobs-headers", + type: { + name: "Composite", + className: "ContainerFilterBlobsHeaders", + modelProperties: { + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ContainerAcquireLeaseHeaders: msRest.CompositeMapper = { + serializedName: "container-acquirelease-headers", + type: { + name: "Composite", + className: "ContainerAcquireLeaseHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + leaseId: { + serializedName: "x-ms-lease-id", + type: { + name: "String" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ContainerReleaseLeaseHeaders: msRest.CompositeMapper = { + serializedName: "container-releaselease-headers", + type: { + name: "Composite", + className: "ContainerReleaseLeaseHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ContainerRenewLeaseHeaders: msRest.CompositeMapper = { + serializedName: "container-renewlease-headers", + type: { + name: "Composite", + className: "ContainerRenewLeaseHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + leaseId: { + serializedName: "x-ms-lease-id", + type: { + name: "String" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ContainerBreakLeaseHeaders: msRest.CompositeMapper = { + serializedName: "container-breaklease-headers", + type: { + name: "Composite", + className: "ContainerBreakLeaseHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + leaseTime: { + serializedName: "x-ms-lease-time", + type: { + name: "Number" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ContainerChangeLeaseHeaders: msRest.CompositeMapper = { + serializedName: "container-changelease-headers", + type: { + name: "Composite", + className: "ContainerChangeLeaseHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + leaseId: { + serializedName: "x-ms-lease-id", + type: { + name: "String" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ContainerGetAccountInfoHeaders: msRest.CompositeMapper = { + serializedName: "container-getaccountinfo-headers", + type: { + name: "Composite", + className: "ContainerGetAccountInfoHeaders", + modelProperties: { + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + skuName: { + serializedName: "x-ms-sku-name", + type: { + name: "Enum", + allowedValues: [ + "Standard_LRS", + "Standard_GRS", + "Standard_RAGRS", + "Standard_ZRS", + "Premium_LRS" + ] + } + }, + accountKind: { + serializedName: "x-ms-account-kind", + type: { + name: "Enum", + allowedValues: [ + "Storage", + "BlobStorage", + "StorageV2", + "FileStorage", + "BlockBlobStorage" + ] + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ContainerGetAccountInfoWithHeadHeaders: msRest.CompositeMapper = { + serializedName: "container-getaccountinfowithhead-headers", + type: { + name: "Composite", + className: "ContainerGetAccountInfoWithHeadHeaders", + modelProperties: { + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + skuName: { + serializedName: "x-ms-sku-name", + type: { + name: "Enum", + allowedValues: [ + "Standard_LRS", + "Standard_GRS", + "Standard_RAGRS", + "Standard_ZRS", + "Premium_LRS" + ] + } + }, + accountKind: { + serializedName: "x-ms-account-kind", + type: { + name: "Enum", + allowedValues: [ + "Storage", + "BlobStorage", + "StorageV2", + "FileStorage", + "BlockBlobStorage" + ] + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const PageBlobCreateHeaders: msRest.CompositeMapper = { + serializedName: "pageblob-create-headers", + type: { + name: "Composite", + className: "PageBlobCreateHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + contentMD5: { + serializedName: "content-md5", + type: { + name: "ByteArray" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + versionId: { + serializedName: "x-ms-version-id", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + isServerEncrypted: { + serializedName: "x-ms-request-server-encrypted", + type: { + name: "Boolean" + } + }, + encryptionKeySha256: { + serializedName: "x-ms-encryption-key-sha256", + type: { + name: "String" + } + }, + encryptionScope: { + serializedName: "x-ms-encryption-scope", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const AppendBlobCreateHeaders: msRest.CompositeMapper = { + serializedName: "appendblob-create-headers", + type: { + name: "Composite", + className: "AppendBlobCreateHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + contentMD5: { + serializedName: "content-md5", + type: { + name: "ByteArray" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + versionId: { + serializedName: "x-ms-version-id", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + isServerEncrypted: { + serializedName: "x-ms-request-server-encrypted", + type: { + name: "Boolean" + } + }, + encryptionKeySha256: { + serializedName: "x-ms-encryption-key-sha256", + type: { + name: "String" + } + }, + encryptionScope: { + serializedName: "x-ms-encryption-scope", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlockBlobUploadHeaders: msRest.CompositeMapper = { + serializedName: "blockblob-upload-headers", + type: { + name: "Composite", + className: "BlockBlobUploadHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + contentMD5: { + serializedName: "content-md5", + type: { + name: "ByteArray" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + versionId: { + serializedName: "x-ms-version-id", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + isServerEncrypted: { + serializedName: "x-ms-request-server-encrypted", + type: { + name: "Boolean" + } + }, + encryptionKeySha256: { + serializedName: "x-ms-encryption-key-sha256", + type: { + name: "String" + } + }, + encryptionScope: { + serializedName: "x-ms-encryption-scope", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlockBlobPutBlobFromUrlHeaders: msRest.CompositeMapper = { + serializedName: "blockblob-putblobfromurl-headers", + type: { + name: "Composite", + className: "BlockBlobPutBlobFromUrlHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + contentMD5: { + serializedName: "content-md5", + type: { + name: "ByteArray" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + versionId: { + serializedName: "x-ms-version-id", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + isServerEncrypted: { + serializedName: "x-ms-request-server-encrypted", + type: { + name: "Boolean" + } + }, + encryptionKeySha256: { + serializedName: "x-ms-encryption-key-sha256", + type: { + name: "String" + } + }, + encryptionScope: { + serializedName: "x-ms-encryption-scope", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlobUndeleteHeaders: msRest.CompositeMapper = { + serializedName: "blob-undelete-headers", + type: { + name: "Composite", + className: "BlobUndeleteHeaders", + modelProperties: { + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlobSetExpiryHeaders: msRest.CompositeMapper = { + serializedName: "blob-setexpiry-headers", + type: { + name: "Composite", + className: "BlobSetExpiryHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlobSetHTTPHeadersHeaders: msRest.CompositeMapper = { + serializedName: "blob-sethttpheaders-headers", + type: { + name: "Composite", + className: "BlobSetHTTPHeadersHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + blobSequenceNumber: { + serializedName: "x-ms-blob-sequence-number", + type: { + name: "Number" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlobSetImmutabilityPolicyHeaders: msRest.CompositeMapper = { + serializedName: "blob-setimmutabilitypolicy-headers", + type: { + name: "Composite", + className: "BlobSetImmutabilityPolicyHeaders", + modelProperties: { + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + immutabilityPolicyExpiry: { + serializedName: "x-ms-immutability-policy-until-date", + type: { + name: "DateTimeRfc1123" + } + }, + immutabilityPolicyMode: { + serializedName: "x-ms-immutability-policy-mode", + type: { + name: "Enum", + allowedValues: [ + "Mutable", + "Unlocked", + "Locked" + ] + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlobDeleteImmutabilityPolicyHeaders: msRest.CompositeMapper = { + serializedName: "blob-deleteimmutabilitypolicy-headers", + type: { + name: "Composite", + className: "BlobDeleteImmutabilityPolicyHeaders", + modelProperties: { + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlobSetLegalHoldHeaders: msRest.CompositeMapper = { + serializedName: "blob-setlegalhold-headers", + type: { + name: "Composite", + className: "BlobSetLegalHoldHeaders", + modelProperties: { + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + legalHold: { + serializedName: "x-ms-legal-hold", + type: { + name: "Boolean" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlobSetMetadataHeaders: msRest.CompositeMapper = { + serializedName: "blob-setmetadata-headers", + type: { + name: "Composite", + className: "BlobSetMetadataHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + versionId: { + serializedName: "x-ms-version-id", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + isServerEncrypted: { + serializedName: "x-ms-request-server-encrypted", + type: { + name: "Boolean" + } + }, + encryptionKeySha256: { + serializedName: "x-ms-encryption-key-sha256", + type: { + name: "String" + } + }, + encryptionScope: { + serializedName: "x-ms-encryption-scope", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlobAcquireLeaseHeaders: msRest.CompositeMapper = { + serializedName: "blob-acquirelease-headers", + type: { + name: "Composite", + className: "BlobAcquireLeaseHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + leaseId: { + serializedName: "x-ms-lease-id", + type: { + name: "String" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlobReleaseLeaseHeaders: msRest.CompositeMapper = { + serializedName: "blob-releaselease-headers", + type: { + name: "Composite", + className: "BlobReleaseLeaseHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlobRenewLeaseHeaders: msRest.CompositeMapper = { + serializedName: "blob-renewlease-headers", + type: { + name: "Composite", + className: "BlobRenewLeaseHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + leaseId: { + serializedName: "x-ms-lease-id", + type: { + name: "String" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlobChangeLeaseHeaders: msRest.CompositeMapper = { + serializedName: "blob-changelease-headers", + type: { + name: "Composite", + className: "BlobChangeLeaseHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + leaseId: { + serializedName: "x-ms-lease-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlobBreakLeaseHeaders: msRest.CompositeMapper = { + serializedName: "blob-breaklease-headers", + type: { + name: "Composite", + className: "BlobBreakLeaseHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + leaseTime: { + serializedName: "x-ms-lease-time", + type: { + name: "Number" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlobCreateSnapshotHeaders: msRest.CompositeMapper = { + serializedName: "blob-createsnapshot-headers", + type: { + name: "Composite", + className: "BlobCreateSnapshotHeaders", + modelProperties: { + snapshot: { + serializedName: "x-ms-snapshot", + type: { + name: "String" + } + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + versionId: { + serializedName: "x-ms-version-id", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + isServerEncrypted: { + serializedName: "x-ms-request-server-encrypted", + type: { + name: "Boolean" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlobStartCopyFromURLHeaders: msRest.CompositeMapper = { + serializedName: "blob-startcopyfromurl-headers", + type: { + name: "Composite", + className: "BlobStartCopyFromURLHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + versionId: { + serializedName: "x-ms-version-id", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + copyId: { + serializedName: "x-ms-copy-id", + type: { + name: "String" + } + }, + copyStatus: { + serializedName: "x-ms-copy-status", + type: { + name: "Enum", + allowedValues: [ + "pending", + "success", + "aborted", + "failed" + ] + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlobCopyFromURLHeaders: msRest.CompositeMapper = { + serializedName: "blob-copyfromurl-headers", + type: { + name: "Composite", + className: "BlobCopyFromURLHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + versionId: { + serializedName: "x-ms-version-id", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + copyId: { + serializedName: "x-ms-copy-id", + type: { + name: "String" + } + }, + copyStatus: { + serializedName: "x-ms-copy-status", + type: { + name: "Enum", + allowedValues: [ + "success" + ] + } + }, + contentMD5: { + serializedName: "content-md5", + type: { + name: "ByteArray" + } + }, + xMsContentCrc64: { + serializedName: "x-ms-content-crc64", + type: { + name: "ByteArray" + } + }, + encryptionScope: { + serializedName: "x-ms-encryption-scope", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlobAbortCopyFromURLHeaders: msRest.CompositeMapper = { + serializedName: "blob-abortcopyfromurl-headers", + type: { + name: "Composite", + className: "BlobAbortCopyFromURLHeaders", + modelProperties: { + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlobSetTierHeaders: msRest.CompositeMapper = { + serializedName: "blob-settier-headers", + type: { + name: "Composite", + className: "BlobSetTierHeaders", + modelProperties: { + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlobGetAccountInfoHeaders: msRest.CompositeMapper = { + serializedName: "blob-getaccountinfo-headers", + type: { + name: "Composite", + className: "BlobGetAccountInfoHeaders", + modelProperties: { + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + skuName: { + serializedName: "x-ms-sku-name", + type: { + name: "Enum", + allowedValues: [ + "Standard_LRS", + "Standard_GRS", + "Standard_RAGRS", + "Standard_ZRS", + "Premium_LRS" + ] + } + }, + accountKind: { + serializedName: "x-ms-account-kind", + type: { + name: "Enum", + allowedValues: [ + "Storage", + "BlobStorage", + "StorageV2", + "FileStorage", + "BlockBlobStorage" + ] + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlobGetAccountInfoWithHeadHeaders: msRest.CompositeMapper = { + serializedName: "blob-getaccountinfowithhead-headers", + type: { + name: "Composite", + className: "BlobGetAccountInfoWithHeadHeaders", + modelProperties: { + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + skuName: { + serializedName: "x-ms-sku-name", + type: { + name: "Enum", + allowedValues: [ + "Standard_LRS", + "Standard_GRS", + "Standard_RAGRS", + "Standard_ZRS", + "Premium_LRS" + ] + } + }, + accountKind: { + serializedName: "x-ms-account-kind", + type: { + name: "Enum", + allowedValues: [ + "Storage", + "BlobStorage", + "StorageV2", + "FileStorage", + "BlockBlobStorage" + ] + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlockBlobStageBlockHeaders: msRest.CompositeMapper = { + serializedName: "blockblob-stageblock-headers", + type: { + name: "Composite", + className: "BlockBlobStageBlockHeaders", + modelProperties: { + contentMD5: { + serializedName: "content-md5", + type: { + name: "ByteArray" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + xMsContentCrc64: { + serializedName: "x-ms-content-crc64", + type: { + name: "ByteArray" + } + }, + isServerEncrypted: { + serializedName: "x-ms-request-server-encrypted", + type: { + name: "Boolean" + } + }, + encryptionKeySha256: { + serializedName: "x-ms-encryption-key-sha256", + type: { + name: "String" + } + }, + encryptionScope: { + serializedName: "x-ms-encryption-scope", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlockBlobStageBlockFromURLHeaders: msRest.CompositeMapper = { + serializedName: "blockblob-stageblockfromurl-headers", + type: { + name: "Composite", + className: "BlockBlobStageBlockFromURLHeaders", + modelProperties: { + contentMD5: { + serializedName: "content-md5", + type: { + name: "ByteArray" + } + }, + xMsContentCrc64: { + serializedName: "x-ms-content-crc64", + type: { + name: "ByteArray" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + isServerEncrypted: { + serializedName: "x-ms-request-server-encrypted", + type: { + name: "Boolean" + } + }, + encryptionKeySha256: { + serializedName: "x-ms-encryption-key-sha256", + type: { + name: "String" + } + }, + encryptionScope: { + serializedName: "x-ms-encryption-scope", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlockBlobCommitBlockListHeaders: msRest.CompositeMapper = { + serializedName: "blockblob-commitblocklist-headers", + type: { + name: "Composite", + className: "BlockBlobCommitBlockListHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + contentMD5: { + serializedName: "content-md5", + type: { + name: "ByteArray" + } + }, + xMsContentCrc64: { + serializedName: "x-ms-content-crc64", + type: { + name: "ByteArray" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + versionId: { + serializedName: "x-ms-version-id", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + isServerEncrypted: { + serializedName: "x-ms-request-server-encrypted", + type: { + name: "Boolean" + } + }, + encryptionKeySha256: { + serializedName: "x-ms-encryption-key-sha256", + type: { + name: "String" + } + }, + encryptionScope: { + serializedName: "x-ms-encryption-scope", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlockBlobGetBlockListHeaders: msRest.CompositeMapper = { + serializedName: "blockblob-getblocklist-headers", + type: { + name: "Composite", + className: "BlockBlobGetBlockListHeaders", + modelProperties: { + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + contentType: { + serializedName: "content-type", + type: { + name: "String" + } + }, + blobContentLength: { + serializedName: "x-ms-blob-content-length", + type: { + name: "Number" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const PageBlobUploadPagesHeaders: msRest.CompositeMapper = { + serializedName: "pageblob-uploadpages-headers", + type: { + name: "Composite", + className: "PageBlobUploadPagesHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + contentMD5: { + serializedName: "content-md5", + type: { + name: "ByteArray" + } + }, + xMsContentCrc64: { + serializedName: "x-ms-content-crc64", + type: { + name: "ByteArray" + } + }, + blobSequenceNumber: { + serializedName: "x-ms-blob-sequence-number", + type: { + name: "Number" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + isServerEncrypted: { + serializedName: "x-ms-request-server-encrypted", + type: { + name: "Boolean" + } + }, + encryptionKeySha256: { + serializedName: "x-ms-encryption-key-sha256", + type: { + name: "String" + } + }, + encryptionScope: { + serializedName: "x-ms-encryption-scope", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const PageBlobClearPagesHeaders: msRest.CompositeMapper = { + serializedName: "pageblob-clearpages-headers", + type: { + name: "Composite", + className: "PageBlobClearPagesHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + contentMD5: { + serializedName: "content-md5", + type: { + name: "ByteArray" + } + }, + xMsContentCrc64: { + serializedName: "x-ms-content-crc64", + type: { + name: "ByteArray" + } + }, + blobSequenceNumber: { + serializedName: "x-ms-blob-sequence-number", + type: { + name: "Number" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const PageBlobUploadPagesFromURLHeaders: msRest.CompositeMapper = { + serializedName: "pageblob-uploadpagesfromurl-headers", + type: { + name: "Composite", + className: "PageBlobUploadPagesFromURLHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + contentMD5: { + serializedName: "content-md5", + type: { + name: "ByteArray" + } + }, + xMsContentCrc64: { + serializedName: "x-ms-content-crc64", + type: { + name: "ByteArray" + } + }, + blobSequenceNumber: { + serializedName: "x-ms-blob-sequence-number", + type: { + name: "Number" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + isServerEncrypted: { + serializedName: "x-ms-request-server-encrypted", + type: { + name: "Boolean" + } + }, + encryptionKeySha256: { + serializedName: "x-ms-encryption-key-sha256", + type: { + name: "String" + } + }, + encryptionScope: { + serializedName: "x-ms-encryption-scope", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const PageBlobGetPageRangesHeaders: msRest.CompositeMapper = { + serializedName: "pageblob-getpageranges-headers", + type: { + name: "Composite", + className: "PageBlobGetPageRangesHeaders", + modelProperties: { + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + blobContentLength: { + serializedName: "x-ms-blob-content-length", + type: { + name: "Number" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const PageBlobGetPageRangesDiffHeaders: msRest.CompositeMapper = { + serializedName: "pageblob-getpagerangesdiff-headers", + type: { + name: "Composite", + className: "PageBlobGetPageRangesDiffHeaders", + modelProperties: { + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + blobContentLength: { + serializedName: "x-ms-blob-content-length", + type: { + name: "Number" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const PageBlobResizeHeaders: msRest.CompositeMapper = { + serializedName: "pageblob-resize-headers", + type: { + name: "Composite", + className: "PageBlobResizeHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + blobSequenceNumber: { + serializedName: "x-ms-blob-sequence-number", + type: { + name: "Number" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const PageBlobUpdateSequenceNumberHeaders: msRest.CompositeMapper = { + serializedName: "pageblob-updatesequencenumber-headers", + type: { + name: "Composite", + className: "PageBlobUpdateSequenceNumberHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + blobSequenceNumber: { + serializedName: "x-ms-blob-sequence-number", + type: { + name: "Number" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const PageBlobCopyIncrementalHeaders: msRest.CompositeMapper = { + serializedName: "pageblob-copyincremental-headers", + type: { + name: "Composite", + className: "PageBlobCopyIncrementalHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + copyId: { + serializedName: "x-ms-copy-id", + type: { + name: "String" + } + }, + copyStatus: { + serializedName: "x-ms-copy-status", + type: { + name: "Enum", + allowedValues: [ + "pending", + "success", + "aborted", + "failed" + ] + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const AppendBlobAppendBlockHeaders: msRest.CompositeMapper = { + serializedName: "appendblob-appendblock-headers", + type: { + name: "Composite", + className: "AppendBlobAppendBlockHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + contentMD5: { + serializedName: "content-md5", + type: { + name: "ByteArray" + } + }, + xMsContentCrc64: { + serializedName: "x-ms-content-crc64", + type: { + name: "ByteArray" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + blobAppendOffset: { + serializedName: "x-ms-blob-append-offset", + type: { + name: "String" + } + }, + blobCommittedBlockCount: { + serializedName: "x-ms-blob-committed-block-count", + type: { + name: "Number" + } + }, + isServerEncrypted: { + serializedName: "x-ms-request-server-encrypted", + type: { + name: "Boolean" + } + }, + encryptionKeySha256: { + serializedName: "x-ms-encryption-key-sha256", + type: { + name: "String" + } + }, + encryptionScope: { + serializedName: "x-ms-encryption-scope", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const AppendBlobAppendBlockFromUrlHeaders: msRest.CompositeMapper = { + serializedName: "appendblob-appendblockfromurl-headers", + type: { + name: "Composite", + className: "AppendBlobAppendBlockFromUrlHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + contentMD5: { + serializedName: "content-md5", + type: { + name: "ByteArray" + } + }, + xMsContentCrc64: { + serializedName: "x-ms-content-crc64", + type: { + name: "ByteArray" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + blobAppendOffset: { + serializedName: "x-ms-blob-append-offset", + type: { + name: "String" + } + }, + blobCommittedBlockCount: { + serializedName: "x-ms-blob-committed-block-count", + type: { + name: "Number" + } + }, + encryptionKeySha256: { + serializedName: "x-ms-encryption-key-sha256", + type: { + name: "String" + } + }, + encryptionScope: { + serializedName: "x-ms-encryption-scope", + type: { + name: "String" + } + }, + isServerEncrypted: { + serializedName: "x-ms-request-server-encrypted", + type: { + name: "Boolean" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const AppendBlobSealHeaders: msRest.CompositeMapper = { + serializedName: "appendblob-seal-headers", + type: { + name: "Composite", + className: "AppendBlobSealHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + isSealed: { + serializedName: "x-ms-blob-sealed", + type: { + name: "Boolean" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlobQueryHeaders: msRest.CompositeMapper = { + serializedName: "blob-query-headers", + type: { + name: "Composite", + className: "BlobQueryHeaders", + modelProperties: { + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + metadata: { + serializedName: "x-ms-meta", + type: { + name: "Dictionary", + value: { + type: { + name: "String" + } + } + }, + headerCollectionPrefix: "x-ms-meta-" + }, + contentLength: { + serializedName: "content-length", + type: { + name: "Number" + } + }, + contentType: { + serializedName: "content-type", + type: { + name: "String" + } + }, + contentRange: { + serializedName: "content-range", + type: { + name: "String" + } + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + contentMD5: { + serializedName: "content-md5", + type: { + name: "ByteArray" + } + }, + contentEncoding: { + serializedName: "content-encoding", + type: { + name: "String" + } + }, + cacheControl: { + serializedName: "cache-control", + type: { + name: "String" + } + }, + contentDisposition: { + serializedName: "content-disposition", + type: { + name: "String" + } + }, + contentLanguage: { + serializedName: "content-language", + type: { + name: "String" + } + }, + blobSequenceNumber: { + serializedName: "x-ms-blob-sequence-number", + type: { + name: "Number" + } + }, + blobType: { + serializedName: "x-ms-blob-type", + type: { + name: "Enum", + allowedValues: [ + "BlockBlob", + "PageBlob", + "AppendBlob" + ] + } + }, + copyCompletionTime: { + serializedName: "x-ms-copy-completion-time", + type: { + name: "DateTimeRfc1123" + } + }, + copyStatusDescription: { + serializedName: "x-ms-copy-status-description", + type: { + name: "String" + } + }, + copyId: { + serializedName: "x-ms-copy-id", + type: { + name: "String" + } + }, + copyProgress: { + serializedName: "x-ms-copy-progress", + type: { + name: "String" + } + }, + copySource: { + serializedName: "x-ms-copy-source", + type: { + name: "String" + } + }, + copyStatus: { + serializedName: "x-ms-copy-status", + type: { + name: "Enum", + allowedValues: [ + "pending", + "success", + "aborted", + "failed" + ] + } + }, + leaseDuration: { + serializedName: "x-ms-lease-duration", + type: { + name: "Enum", + allowedValues: [ + "infinite", + "fixed" + ] + } + }, + leaseState: { + serializedName: "x-ms-lease-state", + type: { + name: "Enum", + allowedValues: [ + "available", + "leased", + "expired", + "breaking", + "broken" + ] + } + }, + leaseStatus: { + serializedName: "x-ms-lease-status", + type: { + name: "Enum", + allowedValues: [ + "locked", + "unlocked" + ] + } + }, + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + acceptRanges: { + serializedName: "accept-ranges", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + blobCommittedBlockCount: { + serializedName: "x-ms-blob-committed-block-count", + type: { + name: "Number" + } + }, + isServerEncrypted: { + serializedName: "x-ms-server-encrypted", + type: { + name: "Boolean" + } + }, + encryptionKeySha256: { + serializedName: "x-ms-encryption-key-sha256", + type: { + name: "String" + } + }, + encryptionScope: { + serializedName: "x-ms-encryption-scope", + type: { + name: "String" + } + }, + blobContentMD5: { + serializedName: "x-ms-blob-content-md5", + type: { + name: "ByteArray" + } + }, + contentCrc64: { + serializedName: "x-ms-content-crc64", + type: { + name: "ByteArray" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlobGetTagsHeaders: msRest.CompositeMapper = { + serializedName: "blob-gettags-headers", + type: { + name: "Composite", + className: "BlobGetTagsHeaders", + modelProperties: { + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const BlobSetTagsHeaders: msRest.CompositeMapper = { + serializedName: "blob-settags-headers", + type: { + name: "Composite", + className: "BlobSetTagsHeaders", + modelProperties: { + clientRequestId: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; diff --git a/src/dfs/generated/artifacts/models.ts b/src/dfs/generated/artifacts/models.ts new file mode 100644 index 000000000..cd63967b5 --- /dev/null +++ b/src/dfs/generated/artifacts/models.ts @@ -0,0 +1,10261 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// tslint:disable:max-line-length +// tslint:disable:interface-name +// tslint:disable:quotemark + +/** + * An interface representing AclFailedEntry. + */ +export interface AclFailedEntry { + name?: string; + type?: string; + errorMessage?: string; +} + +/** + * An interface representing SetAccessControlRecursiveResponse. + */ +export interface SetAccessControlRecursiveResponse { + directoriesSuccessful?: number; + filesSuccessful?: number; + failureCount?: number; + failedEntries?: AclFailedEntry[]; +} + +/** + * An interface representing Path. + */ +export interface Path { + name?: string; + /** + * Default value: false. + */ + isDirectory?: boolean; + lastModified?: Date; + etag?: string; + contentLength?: number; + owner?: string; + group?: string; + permissions?: string; + /** + * The name of the encryption scope under which the blob is encrypted. + */ + encryptionScope?: string; +} + +/** + * An interface representing PathList. + */ +export interface PathList { + paths?: Path[]; +} + +/** + * An interface representing FileSystem. + */ +export interface FileSystem { + name?: string; + lastModified?: string; + eTag?: string; +} + +/** + * Properties of a blob + */ +export interface BlobPropertiesInternal { + creationTime?: Date; + lastModified: Date; + etag: string; + /** + * Size in bytes + */ + contentLength?: number; + contentType?: string; + contentEncoding?: string; + contentLanguage?: string; + contentMD5?: Uint8Array; + contentDisposition?: string; + cacheControl?: string; + blobSequenceNumber?: number; + copyId?: string; + copySource?: string; + copyProgress?: string; + copyCompletionTime?: Date; + copyStatusDescription?: string; + serverEncrypted?: boolean; + incrementalCopy?: boolean; + destinationSnapshot?: string; + deletedTime?: Date; + remainingRetentionDays?: number; + accessTierInferred?: boolean; + customerProvidedKeySha256?: string; + /** + * The name of the encryption scope under which the blob is encrypted. + */ + encryptionScope?: string; + accessTierChangeTime?: Date; + tagCount?: number; + expiresOn?: Date; + isSealed?: boolean; + lastAccessedOn?: Date; + deleteTime?: Date; + properties?: string; + /** + * Possible values include: 'BlockBlob', 'PageBlob', 'AppendBlob' + */ + blobType?: BlobType; + /** + * Possible values include: 'locked', 'unlocked' + */ + leaseStatus?: LeaseStatusType; + /** + * Possible values include: 'available', 'leased', 'expired', 'breaking', 'broken' + */ + leaseState?: LeaseStateType; + /** + * Possible values include: 'infinite', 'fixed' + */ + leaseDuration?: LeaseDurationType; + /** + * Possible values include: 'pending', 'success', 'aborted', 'failed' + */ + copyStatus?: CopyStatusType; + /** + * Possible values include: 'P4', 'P6', 'P10', 'P15', 'P20', 'P30', 'P40', 'P50', 'P60', 'P70', + * 'P80', 'Hot', 'Cool', 'Archive', 'Premium' + */ + accessTier?: AccessTier; + /** + * Possible values include: 'rehydrate-pending-to-hot', 'rehydrate-pending-to-cool' + */ + archiveStatus?: ArchiveStatus; + /** + * Possible values include: 'High', 'Standard' + */ + rehydratePriority?: RehydratePriority; + immutabilityPolicyExpiresOn?: Date; + /** + * Possible values include: 'Mutable', 'Unlocked', 'Locked' + */ + immutabilityPolicyMode?: BlobImmutabilityPolicyMode; + legalHold?: boolean; +} + +/** + * An interface representing BlobMetadata. + */ +export interface BlobMetadata { + encrypted?: string; + /** + * Describes unknown properties. The value of an unknown property MUST be of type "string". Due + * to valid TS constraints we have modeled this as a union of `string | any`. + */ + [property: string]: string | any; +} + +/** + * An interface representing BlobTag. + */ +export interface BlobTag { + key: string; + value: string; +} + +/** + * Blob tags + */ +export interface BlobTags { + blobTagSet: BlobTag[]; +} + +/** + * An Azure Storage blob + */ +export interface BlobItemInternal { + name: string; + deleted?: boolean; + snapshot?: string; + versionId?: string; + isCurrentVersion?: boolean; + properties: BlobPropertiesInternal; + deletionId?: string; + metadata?: BlobMetadata; + blobTags?: BlobTags; + objectReplicationMetadata?: { [propertyName: string]: string }; + hasVersionsOnly?: boolean; +} + +/** + * An interface representing BlobFlatListSegment. + */ +export interface BlobFlatListSegment { + blobItems: BlobItemInternal[]; +} + +/** + * An enumeration of blobs + */ +export interface ListBlobsFlatSegmentResponse { + serviceEndpoint: string; + containerName: string; + prefix?: string; + marker?: string; + maxResults?: number; + segment: BlobFlatListSegment; + nextMarker?: string; +} + +/** + * An interface representing BlobPrefix. + */ +export interface BlobPrefix { + name: string; +} + +/** + * An interface representing BlobHierarchyListSegment. + */ +export interface BlobHierarchyListSegment { + blobPrefixes?: BlobPrefix[]; + blobItems: BlobItemInternal[]; +} + +/** + * An enumeration of blobs + */ +export interface ListBlobsHierarchySegmentResponse { + serviceEndpoint: string; + containerName: string; + prefix?: string; + marker?: string; + maxResults?: number; + delimiter?: string; + segment: BlobHierarchyListSegment; + nextMarker?: string; +} + +/** + * An interface representing FileSystemList. + */ +export interface FileSystemList { + filesystems?: FileSystem[]; +} + +/** + * The service error response object. + */ +export interface StorageErrorError { + /** + * The service error code. + */ + code?: string; + /** + * The service error message. + */ + message?: string; +} + +/** + * An interface representing StorageError. + */ +export interface StorageError { + /** + * The service error message. + */ + message?: string; + /** + * The service error response object. + */ + error?: StorageErrorError; +} + +/** + * Key information + */ +export interface KeyInfo { + /** + * The date-time the key is active in ISO 8601 UTC time + */ + start: string; + /** + * The date-time the key expires in ISO 8601 UTC time + */ + expiry: string; +} + +/** + * A user delegation key + */ +export interface UserDelegationKey { + /** + * The Azure Active Directory object ID in GUID format. + */ + signedOid: string; + /** + * The Azure Active Directory tenant ID in GUID format + */ + signedTid: string; + /** + * The date-time the key is active + * **NOTE: This entity will be treated as a string instead of a Date because the API can + * potentially deal with a higher precision value than what is supported by JavaScript.** + */ + signedStart: string; + /** + * The date-time the key expires + * **NOTE: This entity will be treated as a string instead of a Date because the API can + * potentially deal with a higher precision value than what is supported by JavaScript.** + */ + signedExpiry: string; + /** + * Abbreviation of the Azure Storage service that accepts the key + */ + signedService: string; + /** + * The service version that created the key + */ + signedVersion: string; + /** + * The key as a base64 string + */ + value: string; +} + +/** + * An Access policy + */ +export interface AccessPolicy { + /** + * the date-time the policy is active + * **NOTE: This entity will be treated as a string instead of a Date because the API can + * potentially deal with a higher precision value than what is supported by JavaScript.** + */ + start?: string; + /** + * the date-time the policy expires + * **NOTE: This entity will be treated as a string instead of a Date because the API can + * potentially deal with a higher precision value than what is supported by JavaScript.** + */ + expiry?: string; + /** + * the permissions for the acl policy + */ + permission?: string; +} + +/** + * An interface representing BlobName. + */ +export interface BlobName { + /** + * Indicates if the blob name is encoded. + */ + encoded?: boolean; + /** + * The name of the blob. + */ + content?: string; +} + +/** + * Represents a single block in a block blob. It describes the block's ID and size. + */ +export interface Block { + /** + * The base64 encoded block ID. + */ + name: string; + /** + * The block size in bytes. + */ + size: number; +} + +/** + * An interface representing BlockList. + */ +export interface BlockList { + committedBlocks?: Block[]; + uncommittedBlocks?: Block[]; +} + +/** + * An interface representing BlockLookupList. + */ +export interface BlockLookupList { + committed?: string[]; + uncommitted?: string[]; + latest?: string[]; +} + +/** + * Properties of a container + */ +export interface ContainerProperties { + lastModified: Date; + etag: string; + /** + * Possible values include: 'locked', 'unlocked' + */ + leaseStatus?: LeaseStatusType; + /** + * Possible values include: 'available', 'leased', 'expired', 'breaking', 'broken' + */ + leaseState?: LeaseStateType; + /** + * Possible values include: 'infinite', 'fixed' + */ + leaseDuration?: LeaseDurationType; + /** + * Possible values include: 'container', 'blob' + */ + publicAccess?: PublicAccessType; + hasImmutabilityPolicy?: boolean; + hasLegalHold?: boolean; + defaultEncryptionScope?: string; + preventEncryptionScopeOverride?: boolean; + deletedTime?: Date; + remainingRetentionDays?: number; + /** + * Indicates if version level worm is enabled on this container. + */ + isImmutableStorageWithVersioningEnabled?: boolean; +} + +/** + * An Azure Storage container + */ +export interface ContainerItem { + name: string; + deleted?: boolean; + version?: string; + properties: ContainerProperties; + metadata?: { [propertyName: string]: string }; +} + +/** + * Groups the settings used for interpreting the blob data if the blob is delimited text formatted. + */ +export interface DelimitedTextConfiguration { + /** + * The string used to separate columns. + */ + columnSeparator?: string; + /** + * The string used to quote a specific field. + */ + fieldQuote?: string; + /** + * The string used to separate records. + */ + recordSeparator?: string; + /** + * The string used as an escape character. + */ + escapeChar?: string; + /** + * Represents whether the data has headers. + */ + headersPresent?: boolean; +} + +/** + * json text configuration + */ +export interface JsonTextConfiguration { + /** + * The string used to separate records. + */ + recordSeparator?: string; +} + +/** + * Groups settings regarding specific field of an arrow schema + */ +export interface ArrowField { + type: string; + name?: string; + precision?: number; + scale?: number; +} + +/** + * Groups the settings used for formatting the response if the response should be Arrow formatted. + */ +export interface ArrowConfiguration { + schema: ArrowField[]; +} + +/** + * An enumeration of containers + */ +export interface ListContainersSegmentResponse { + serviceEndpoint: string; + prefix?: string; + marker?: string; + maxResults?: number; + containerItems: ContainerItem[]; + nextMarker?: string; +} + +/** + * CORS is an HTTP feature that enables a web application running under one domain to access + * resources in another domain. Web browsers implement a security restriction known as same-origin + * policy that prevents a web page from calling APIs in a different domain; CORS provides a secure + * way to allow one domain (the origin domain) to call APIs in another domain + */ +export interface CorsRule { + /** + * The origin domains that are permitted to make a request against the storage service via CORS. + * The origin domain is the domain from which the request originates. Note that the origin must + * be an exact case-sensitive match with the origin that the user age sends to the service. You + * can also use the wildcard character '*' to allow all origin domains to make requests via CORS. + */ + allowedOrigins: string; + /** + * The methods (HTTP request verbs) that the origin domain may use for a CORS request. (comma + * separated) + */ + allowedMethods: string; + /** + * the request headers that the origin domain may specify on the CORS request. + */ + allowedHeaders?: string; + /** + * The response headers that may be sent in the response to the CORS request and exposed by the + * browser to the request issuer + */ + exposedHeaders?: string; + /** + * The maximum amount time that a browser should cache the preflight OPTIONS request. + */ + maxAgeInSeconds: number; +} + +/** + * Blob info from a Filter Blobs API call + */ +export interface FilterBlobItem { + name: string; + containerName: string; + tags?: BlobTags; + versionId?: string; + isCurrentVersion?: boolean; +} + +/** + * The result of a Filter Blobs API call + */ +export interface FilterBlobSegment { + serviceEndpoint: string; + where: string; + blobs: FilterBlobItem[]; + nextMarker?: string; +} + +/** + * Geo-Replication information for the Secondary Storage Service + */ +export interface GeoReplication { + /** + * The status of the secondary location. Possible values include: 'live', 'bootstrap', + * 'unavailable' + */ + status: GeoReplicationStatusType; + /** + * A GMT date/time value, to the second. All primary writes preceding this value are guaranteed + * to be available for read operations at the secondary. Primary writes after this point in time + * may or may not be available for reads. + */ + lastSyncTime: Date; +} + +/** + * the retention policy which determines how long the associated data should persist + */ +export interface RetentionPolicy { + /** + * Indicates whether a retention policy is enabled for the storage service + */ + enabled: boolean; + /** + * Indicates the number of days that metrics or logging or soft-deleted data should be retained. + * All data older than this value will be deleted + */ + days?: number; + /** + * Indicates whether permanent delete is allowed on this storage account. + */ + allowPermanentDelete?: boolean; +} + +/** + * Azure Analytics Logging settings. + */ +export interface Logging { + /** + * The version of Storage Analytics to configure. + */ + version: string; + /** + * Indicates whether all delete requests should be logged. + */ + deleteProperty: boolean; + /** + * Indicates whether all read requests should be logged. + */ + read: boolean; + /** + * Indicates whether all write requests should be logged. + */ + write: boolean; + retentionPolicy: RetentionPolicy; +} + +/** + * a summary of request statistics grouped by API in hour or minute aggregates for blobs + */ +export interface Metrics { + /** + * The version of Storage Analytics to configure. + */ + version?: string; + /** + * Indicates whether metrics are enabled for the Blob service. + */ + enabled: boolean; + /** + * Indicates whether metrics should generate summary statistics for called API operations. + */ + includeAPIs?: boolean; + retentionPolicy?: RetentionPolicy; +} + +/** + * An interface representing PageRange. + */ +export interface PageRange { + start: number; + end: number; +} + +/** + * An interface representing ClearRange. + */ +export interface ClearRange { + start: number; + end: number; +} + +/** + * the list of pages + */ +export interface PageList { + pageRange?: PageRange[]; + clearRange?: ClearRange[]; + nextMarker?: string; +} + +/** + * An interface representing QueryFormat. + */ +export interface QueryFormat { + /** + * Possible values include: 'delimited', 'json', 'arrow', 'parquet' + */ + type: QueryFormatType; + delimitedTextConfiguration?: DelimitedTextConfiguration; + jsonTextConfiguration?: JsonTextConfiguration; + arrowConfiguration?: ArrowConfiguration; + parquetTextConfiguration?: any; +} + +/** + * An interface representing QuerySerialization. + */ +export interface QuerySerialization { + format: QueryFormat; +} + +/** + * Groups the set of query request settings. + */ +export interface QueryRequest { + /** + * The query expression in SQL. The maximum size of the query expression is 256KiB. + */ + expression: string; + inputSerialization?: QuerySerialization; + outputSerialization?: QuerySerialization; +} + +/** + * signed identifier + */ +export interface SignedIdentifier { + /** + * a unique id + */ + id: string; + accessPolicy: AccessPolicy; +} + +/** + * The properties that enable an account to host a static website + */ +export interface StaticWebsite { + /** + * Indicates whether this account is hosting a static website + */ + enabled: boolean; + /** + * The default name of the index page under each directory + */ + indexDocument?: string; + /** + * The absolute path of the custom 404 page + */ + errorDocument404Path?: string; + /** + * Absolute path of the default index page + */ + defaultIndexDocumentPath?: string; +} + +/** + * Storage Service Properties. + */ +export interface StorageServiceProperties { + logging?: Logging; + hourMetrics?: Metrics; + minuteMetrics?: Metrics; + /** + * The set of CORS rules. + */ + cors?: CorsRule[]; + /** + * The default version to use for requests to the Blob service if an incoming request's version + * is not specified. Possible values include version 2008-10-27 and all more recent versions + */ + defaultServiceVersion?: string; + deleteRetentionPolicy?: RetentionPolicy; + staticWebsite?: StaticWebsite; +} + +/** + * Stats for the storage service. + */ +export interface StorageServiceStats { + geoReplication?: GeoReplication; +} + +/** + * Additional parameters for a set of operations. + */ +export interface ModifiedAccessConditions { + /** + * Specify this header value to operate only on a blob if it has been modified since the + * specified date/time. + */ + ifModifiedSince?: Date; + /** + * Specify this header value to operate only on a blob if it has not been modified since the + * specified date/time. + */ + ifUnmodifiedSince?: Date; + /** + * Specify an ETag value to operate only on blobs with a matching value. + */ + ifMatch?: string; + /** + * Specify an ETag value to operate only on blobs without a matching value. + */ + ifNoneMatch?: string; + /** + * Specify a SQL where clause on blob tags to operate only on blobs with a matching value. + */ + ifTags?: string; +} + +/** + * Additional parameters for a set of operations. + */ +export interface PathHTTPHeaders { + /** + * Optional. Sets the blob's cache control. If specified, this property is stored with the blob + * and returned with a read request. + */ + cacheControl?: string; + /** + * Optional. Sets the blob's content encoding. If specified, this property is stored with the + * blob and returned with a read request. + */ + contentEncoding?: string; + /** + * Optional. Set the blob's content language. If specified, this property is stored with the blob + * and returned with a read request. + */ + contentLanguage?: string; + /** + * Optional. Sets the blob's Content-Disposition header. + */ + contentDisposition?: string; + /** + * Optional. Sets the blob's content type. If specified, this property is stored with the blob + * and returned with a read request. + */ + contentType?: string; + /** + * Specify the transactional md5 for the body, to be validated by the service. + */ + contentMD5?: Uint8Array; + /** + * Specify the transactional md5 for the body, to be validated by the service. + */ + transactionalContentHash?: Uint8Array; +} + +/** + * Additional parameters for a set of operations. + */ +export interface LeaseAccessConditions { + /** + * If specified, the operation only succeeds if the resource's lease is active and matches this + * ID. + */ + leaseId?: string; +} + +/** + * Additional parameters for a set of operations. + */ +export interface SourceModifiedAccessConditions { + /** + * Specify an ETag value to operate only on blobs with a matching value. + */ + sourceIfMatch?: string; + /** + * Specify an ETag value to operate only on blobs without a matching value. + */ + sourceIfNoneMatch?: string; + /** + * Specify this header value to operate only on a blob if it has been modified since the + * specified date/time. + */ + sourceIfModifiedSince?: Date; + /** + * Specify this header value to operate only on a blob if it has not been modified since the + * specified date/time. + */ + sourceIfUnmodifiedSince?: Date; + /** + * Specify a SQL where clause on blob tags to operate only on blobs with a matching value. + */ + sourceIfTags?: string; +} + +/** + * Additional parameters for a set of operations. + */ +export interface CpkInfo { + /** + * Optional. Specifies the encryption key to use to encrypt the data provided in the request. If + * not specified, encryption is performed with the root account encryption key. For more + * information, see Encryption at Rest for Azure Storage Services. + */ + encryptionKey?: string; + /** + * The SHA-256 hash of the provided encryption key. Must be provided if the x-ms-encryption-key + * header is provided. + */ + encryptionKeySha256?: string; + /** + * The algorithm used to produce the encryption key hash. Currently, the only accepted value is + * "AES256". Must be provided if the x-ms-encryption-key header is provided. Possible values + * include: 'AES256' + */ + encryptionAlgorithm?: EncryptionAlgorithmType; +} + +/** + * Additional parameters for create operation. + */ +export interface ContainerCpkScopeInfo { + /** + * Optional. Version 2019-07-07 and later. Specifies the default encryption scope to set on the + * container and use for all future writes. + */ + defaultEncryptionScope?: string; + /** + * Optional. Version 2019-07-07 and newer. If true, prevents any request from specifying a + * different encryption scope than the scope set on the container. + */ + preventEncryptionScopeOverride?: boolean; +} + +/** + * Additional parameters for a set of operations. + */ +export interface BlobHTTPHeaders { + /** + * Optional. Sets the blob's content type. If specified, this property is stored with the blob + * and returned with a read request. + */ + blobContentType?: string; + /** + * Optional. Sets the blob's content encoding. If specified, this property is stored with the + * blob and returned with a read request. + */ + blobContentEncoding?: string; + /** + * Optional. Set the blob's content language. If specified, this property is stored with the blob + * and returned with a read request. + */ + blobContentLanguage?: string; + /** + * Optional. An MD5 hash of the blob content. Note that this hash is not validated, as the hashes + * for the individual blocks were validated when each was uploaded. + */ + blobContentMD5?: Uint8Array; + /** + * Optional. Sets the blob's cache control. If specified, this property is stored with the blob + * and returned with a read request. + */ + blobCacheControl?: string; + /** + * Optional. Sets the blob's Content-Disposition header. + */ + blobContentDisposition?: string; +} + +/** + * Additional parameters for a set of operations. + */ +export interface CpkScopeInfo { + /** + * Optional. Version 2019-07-07 and later. Specifies the name of the encryption scope to use to + * encrypt the data provided in the request. If not specified, encryption is performed with the + * default account encryption scope. For more information, see Encryption at Rest for Azure + * Storage Services. + */ + encryptionScope?: string; +} + +/** + * Additional parameters for a set of operations, such as: PageBlob_uploadPages, + * PageBlob_clearPages, PageBlob_uploadPagesFromURL. + */ +export interface SequenceNumberAccessConditions { + /** + * Specify this header value to operate only on a blob if it has a sequence number less than or + * equal to the specified. + */ + ifSequenceNumberLessThanOrEqualTo?: number; + /** + * Specify this header value to operate only on a blob if it has a sequence number less than the + * specified. + */ + ifSequenceNumberLessThan?: number; + /** + * Specify this header value to operate only on a blob if it has the specified sequence number. + */ + ifSequenceNumberEqualTo?: number; +} + +/** + * Additional parameters for a set of operations, such as: AppendBlob_appendBlock, + * AppendBlob_appendBlockFromUrl, AppendBlob_seal. + */ +export interface AppendPositionAccessConditions { + /** + * Optional conditional header. The max length in bytes permitted for the append blob. If the + * Append Block operation would cause the blob to exceed that limit or if the blob size is + * already greater than the value specified in this header, the request will fail with + * MaxBlobSizeConditionNotMet error (HTTP status code 412 - Precondition Failed). + */ + maxSize?: number; + /** + * Optional conditional header, used only for the Append Block operation. A number indicating the + * byte offset to compare. Append Block will succeed only if the append position is equal to this + * number. If it is not, the request will fail with the AppendPositionConditionNotMet error (HTTP + * status code 412 - Precondition Failed). + */ + appendPosition?: number; +} + +/** + * An interface representing DataLakeStorageClientOptions. + */ +export interface DataLakeStorageClientOptions { + /** + * Specifies the version of the operation to use for this request. + */ + version?: string; + /** + * The lease duration is required to acquire a lease, and specifies the duration of the lease in + * seconds. The lease duration must be between 15 and 60 seconds or -1 for infinite lease. + */ + xMsLeaseDuration?: number; +} + +/** + * Optional Parameters. + */ +export interface ServiceListFileSystemsOptionalParams { + /** + * Filters results to filesystems within the specified prefix. + */ + prefix?: string; + /** + * Optional. When deleting a directory, the number of paths that are deleted with each + * invocation is limited. If the number of paths to be deleted exceeds this limit, a + * continuation token is returned in this response header. When a continuation token is returned + * in the response, it must be specified in a subsequent invocation of the delete operation to + * continue deleting the directory. + */ + continuation?: string; + /** + * An optional value that specifies the maximum number of items to return. If omitted or greater + * than 5,000, the response will include up to 5,000 items. + */ + maxResults?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; +} + +/** + * Optional Parameters. + */ +export interface ServiceSetPropertiesOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; +} + +/** + * Optional Parameters. + */ +export interface ServiceGetPropertiesOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; +} + +/** + * Optional Parameters. + */ +export interface ServiceGetStatisticsOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; +} + +/** + * Optional Parameters. + */ +export interface ServiceListContainersSegmentOptionalParams { + /** + * Filters results to filesystems within the specified prefix. + */ + prefix?: string; + /** + * A string value that identifies the portion of the list of containers to be returned with the + * next listing operation. The operation returns the NextMarker value within the response body if + * the listing operation did not return all containers remaining to be listed with the current + * page. The NextMarker value can be used as the value for the marker parameter in a subsequent + * call to request the next page of list items. The marker value is opaque to the client. + */ + marker?: string; + /** + * Specifies the maximum number of containers to return. If the request does not specify + * maxresults, or specifies a value greater than 5000, the server will return up to 5000 items. + * Note that if the listing operation crosses a partition boundary, then the service will return + * a continuation token for retrieving the remainder of the results. For this reason, it is + * possible that the service will return fewer results than specified by maxresults, or than the + * default of 5000. + */ + maxresults?: number; + /** + * Include this parameter to specify that the container's metadata be returned as part of the + * response body. + */ + include?: ListContainersIncludeType[]; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; +} + +/** + * Optional Parameters. + */ +export interface ServiceGetUserDelegationKeyOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; +} + +/** + * Optional Parameters. + */ +export interface ServiceSubmitBatchOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; +} + +/** + * Optional Parameters. + */ +export interface ServiceFilterBlobsOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Filters the results to return only to return only blobs whose tags match the specified + * expression. + */ + where?: string; + /** + * A string value that identifies the portion of the list of containers to be returned with the + * next listing operation. The operation returns the NextMarker value within the response body if + * the listing operation did not return all containers remaining to be listed with the current + * page. The NextMarker value can be used as the value for the marker parameter in a subsequent + * call to request the next page of list items. The marker value is opaque to the client. + */ + marker?: string; + /** + * Specifies the maximum number of containers to return. If the request does not specify + * maxresults, or specifies a value greater than 5000, the server will return up to 5000 items. + * Note that if the listing operation crosses a partition boundary, then the service will return + * a continuation token for retrieving the remainder of the results. For this reason, it is + * possible that the service will return fewer results than specified by maxresults, or than the + * default of 5000. + */ + maxresults?: number; + /** + * Include this parameter to specify one or more datasets to include in the response. + */ + include?: FilterBlobsIncludeItem[]; +} + +/** + * Optional Parameters. + */ +export interface FileSystemCreateOptionalParams { + /** + * Optional. User-defined properties to be stored with the filesystem, in the format of a + * comma-separated list of name and value pairs "n1=v1, n2=v2, ...", where each value is a base64 + * encoded string. Note that the string may only contain ASCII characters in the ISO-8859-1 + * character set. If the filesystem exists, any properties not included in the list will be + * removed. All properties are removed if the header is omitted. To merge new and existing + * properties, first get all existing properties and the current E-Tag, then make a conditional + * request with the E-Tag and include values for all properties. + */ + properties?: string; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; +} + +/** + * Optional Parameters. + */ +export interface FileSystemSetPropertiesOptionalParams { + /** + * Optional. User-defined properties to be stored with the filesystem, in the format of a + * comma-separated list of name and value pairs "n1=v1, n2=v2, ...", where each value is a base64 + * encoded string. Note that the string may only contain ASCII characters in the ISO-8859-1 + * character set. If the filesystem exists, any properties not included in the list will be + * removed. All properties are removed if the header is omitted. To merge new and existing + * properties, first get all existing properties and the current E-Tag, then make a conditional + * request with the E-Tag and include values for all properties. + */ + properties?: string; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface FileSystemGetPropertiesOptionalParams { + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; +} + +/** + * Optional Parameters. + */ +export interface FileSystemDeleteMethodOptionalParams { + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface FileSystemListPathsOptionalParams { + /** + * Optional. When deleting a directory, the number of paths that are deleted with each + * invocation is limited. If the number of paths to be deleted exceeds this limit, a + * continuation token is returned in this response header. When a continuation token is returned + * in the response, it must be specified in a subsequent invocation of the delete operation to + * continue deleting the directory. + */ + continuation?: string; + /** + * Optional. Filters results to paths within the specified directory. An error occurs if the + * directory does not exist. + */ + path?: string; + /** + * An optional value that specifies the maximum number of items to return. If omitted or greater + * than 5,000, the response will include up to 5,000 items. + */ + maxResults?: number; + /** + * Optional. Valid only when Hierarchical Namespace is enabled for the account. If "true", the + * user identity values returned in the x-ms-owner, x-ms-group, and x-ms-acl response headers + * will be transformed from Azure Active Directory Object IDs to User Principal Names. If + * "false", the values will be returned as Azure Active Directory Object IDs. The default value + * is false. Note that group and application Object IDs are not translated because they do not + * have unique friendly names. + */ + upn?: boolean; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; +} + +/** + * Optional Parameters. + */ +export interface FileSystemListBlobFlatSegmentOptionalParams { + /** + * Filters results to filesystems within the specified prefix. + */ + prefix?: string; + /** + * A string value that identifies the portion of the list of containers to be returned with the + * next listing operation. The operation returns the NextMarker value within the response body if + * the listing operation did not return all containers remaining to be listed with the current + * page. The NextMarker value can be used as the value for the marker parameter in a subsequent + * call to request the next page of list items. The marker value is opaque to the client. + */ + marker?: string; + /** + * An optional value that specifies the maximum number of items to return. If omitted or greater + * than 5,000, the response will include up to 5,000 items. + */ + maxResults?: number; + /** + * Specifies the maximum number of containers to return. If the request does not specify + * maxresults, or specifies a value greater than 5000, the server will return up to 5000 items. + * Note that if the listing operation crosses a partition boundary, then the service will return + * a continuation token for retrieving the remainder of the results. For this reason, it is + * possible that the service will return fewer results than specified by maxresults, or than the + * default of 5000. + */ + maxresults?: number; + /** + * Include this parameter to specify one or more datasets to include in the response. + */ + include?: ListBlobsIncludeItem[]; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; +} + +/** + * Optional Parameters. + */ +export interface FileSystemListBlobHierarchySegmentOptionalParams { + /** + * Filters results to filesystems within the specified prefix. + */ + prefix?: string; + /** + * A string value that identifies the portion of the list of containers to be returned with the + * next listing operation. The operation returns the NextMarker value within the response body if + * the listing operation did not return all containers remaining to be listed with the current + * page. The NextMarker value can be used as the value for the marker parameter in a subsequent + * call to request the next page of list items. The marker value is opaque to the client. + */ + marker?: string; + /** + * An optional value that specifies the maximum number of items to return. If omitted or greater + * than 5,000, the response will include up to 5,000 items. + */ + maxResults?: number; + /** + * Specifies the maximum number of containers to return. If the request does not specify + * maxresults, or specifies a value greater than 5000, the server will return up to 5000 items. + * Note that if the listing operation crosses a partition boundary, then the service will return + * a continuation token for retrieving the remainder of the results. For this reason, it is + * possible that the service will return fewer results than specified by maxresults, or than the + * default of 5000. + */ + maxresults?: number; + /** + * Include this parameter to specify one or more datasets to include in the response. + */ + include?: ListBlobsIncludeItem[]; + /** + * Include this parameter to specify one or more datasets to include in the response. Possible + * values include: 'deleted' + */ + showonly?: ListBlobsShowOnly; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; +} + +/** + * Optional Parameters. + */ +export interface PathCreateOptionalParams { + /** + * Required only for Create File and Create Directory. The value must be "file" or "directory". + * Possible values include: 'directory', 'file' + */ + resource?: PathResourceType; + /** + * Optional. When deleting a directory, the number of paths that are deleted with each + * invocation is limited. If the number of paths to be deleted exceeds this limit, a + * continuation token is returned in this response header. When a continuation token is returned + * in the response, it must be specified in a subsequent invocation of the delete operation to + * continue deleting the directory. + */ + continuation?: string; + /** + * Optional. Valid only when namespace is enabled. This parameter determines the behavior of the + * rename operation. The value must be "legacy" or "posix", and the default value will be + * "posix". Possible values include: 'legacy', 'posix' + */ + mode?: PathRenameMode; + /** + * An optional file or directory to be renamed. The value must have the following format: + * "/{filesystem}/{path}". If "x-ms-properties" is specified, the properties will overwrite the + * existing properties; otherwise, the existing properties will be preserved. This value must be + * a URL percent-encoded string. Note that the string may only contain ASCII characters in the + * ISO-8859-1 character set. + */ + renameSource?: string; + /** + * A lease ID for the source path. If specified, the source path must have an active lease and + * the lease ID must match. + */ + sourceLeaseId?: string; + /** + * Optional. User-defined properties to be stored with the filesystem, in the format of a + * comma-separated list of name and value pairs "n1=v1, n2=v2, ...", where each value is a base64 + * encoded string. Note that the string may only contain ASCII characters in the ISO-8859-1 + * character set. If the filesystem exists, any properties not included in the list will be + * removed. All properties are removed if the header is omitted. To merge new and existing + * properties, first get all existing properties and the current E-Tag, then make a conditional + * request with the E-Tag and include values for all properties. + */ + properties?: string; + /** + * Optional and only valid if Hierarchical Namespace is enabled for the account. Sets POSIX + * access permissions for the file owner, the file owning group, and others. Each class may be + * granted read, write, or execute permission. The sticky bit is also supported. Both symbolic + * (rwxrw-rw-) and 4-digit octal notation (e.g. 0766) are supported. + */ + permissions?: string; + /** + * Optional and only valid if Hierarchical Namespace is enabled for the account. When creating a + * file or directory and the parent folder does not have a default ACL, the umask restricts the + * permissions of the file or directory to be created. The resulting permission is given by p + * bitwise and not u, where p is the permission and u is the umask. For example, if p is 0777 + * and u is 0057, then the resulting permission is 0720. The default permission is 0777 for a + * directory and 0666 for a file. The default umask is 0027. The umask must be specified in + * 4-digit octal notation (e.g. 0766). + */ + umask?: string; + /** + * Optional. The owner of the blob or directory. + */ + owner?: string; + /** + * Optional. The owning group of the blob or directory. + */ + group?: string; + /** + * Sets POSIX access control rights on files and directories. The value is a comma-separated list + * of access control entries. Each access control entry (ACE) consists of a scope, a type, a user + * or group identifier, and permissions in the format "[scope:][type]:[id]:[permissions]". + */ + acl?: string; + /** + * Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if + * the proposed lease ID is not in the correct format. See Guid Constructor (String) for a list + * of valid GUID string formats. + */ + proposedLeaseId?: string; + /** + * The lease duration is required to acquire a lease, and specifies the duration of the lease in + * seconds. The lease duration must be between 15 and 60 seconds or -1 for infinite lease. + */ + leaseDuration?: number; + /** + * Required. Indicates mode of the expiry time. Possible values include: 'NeverExpire', + * 'RelativeToCreation', 'RelativeToNow', 'Absolute' + */ + expiryOptions?: PathExpiryOptions; + /** + * The time to set the blob to expiry + */ + expiresOn?: string; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value + * pairs are specified, the operation will copy the metadata from the source blob or file to the + * destination blob. If one or more name-value pairs are specified, the destination blob is + * created with the specified metadata, and metadata is not copied from the source blob or file. + * Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules + * for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more + * information. + */ + metadata?: { [propertyName: string]: string }; + /** + * Additional parameters for the operation + */ + pathHTTPHeaders?: PathHTTPHeaders; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; + /** + * Additional parameters for the operation + */ + sourceModifiedAccessConditions?: SourceModifiedAccessConditions; + /** + * Additional parameters for the operation + */ + cpkInfo?: CpkInfo; +} + +/** + * Optional Parameters. + */ +export interface PathUpdateOptionalParams { + /** + * Optional. Valid only for append calls. This parameter allows the caller to flush during an + * append call. Default value is 'false' , if 'true' the data will be flushed with the append + * call. Note that when using flush=true, the following headers are not supported - + * 'x-ms-cache-control', 'x-ms-content-encoding', 'x-ms-content-type', 'x-ms-content-language', + * 'x-ms-content-md5', 'x-ms-content-disposition'. To set these headers during flush, please use + * action=flush + */ + flush?: boolean; + /** + * Optional. Valid for "SetAccessControlRecursive" operation. It specifies the maximum number of + * files or directories on which the acl change will be applied. If omitted or greater than + * 2,000, the request will process up to 2,000 items + */ + maxRecords?: number; + /** + * Optional. The number of paths processed with each invocation is limited. If the number of + * paths to be processed exceeds this limit, a continuation token is returned in the response + * header x-ms-continuation. When a continuation token is returned in the response, it must be + * percent-encoded and specified in a subsequent invocation of setAccessControlRecursive + * operation. + */ + continuation?: string; + /** + * Optional. Valid for "SetAccessControlRecursive" operation. If set to false, the operation will + * terminate quickly on encountering user errors (4XX). If true, the operation will ignore user + * errors and proceed with the operation on other sub-entities of the directory. Continuation + * token will only be returned when forceFlag is true in case of user errors. If not set the + * default value is false for this. + */ + forceFlag?: boolean; + /** + * This parameter allows the caller to upload data in parallel and control the order in which it + * is appended to the file. It is required when uploading data to be appended to the file and + * when flushing previously uploaded data to the file. The value must be the position where the + * data is to be appended. Uploaded data is not immediately flushed, or written, to the file. + * To flush, the previously uploaded data must be contiguous, the position parameter must be + * specified and equal to the length of the file after all data has been written, and there must + * not be a request entity body included with the request. + */ + position?: number; + /** + * Valid only for flush operations. If "true", uncommitted data is retained after the flush + * operation completes; otherwise, the uncommitted data is deleted after the flush operation. + * The default is false. Data at offsets less than the specified position are written to the + * file when flush succeeds, but this optional parameter allows data after the flush position to + * be retained for a future flush operation. + */ + retainUncommittedData?: boolean; + /** + * Azure Storage Events allow applications to receive notifications when files change. When Azure + * Storage Events are enabled, a file changed event is raised. This event has a property + * indicating whether this is the final change to distinguish the difference between an + * intermediate flush to a file stream and the final close of a file stream. The close query + * parameter is valid only when the action is "flush" and change notifications are enabled. If + * the value of close is "true" and the flush operation completes successfully, the service + * raises a file change notification with a property indicating that this is the final update + * (the file stream has been closed). If "false" a change notification is raised indicating the + * file has changed. The default is false. This query parameter is set to true by the Hadoop ABFS + * driver to indicate that the file stream has been closed." + */ + close?: boolean; + /** + * Required for "Append Data" and "Flush Data". Must be 0 for "Flush Data". Must be the length + * of the request content in bytes for "Append Data". + */ + contentLength?: number; + /** + * Optional. User-defined properties to be stored with the filesystem, in the format of a + * comma-separated list of name and value pairs "n1=v1, n2=v2, ...", where each value is a base64 + * encoded string. Note that the string may only contain ASCII characters in the ISO-8859-1 + * character set. If the filesystem exists, any properties not included in the list will be + * removed. All properties are removed if the header is omitted. To merge new and existing + * properties, first get all existing properties and the current E-Tag, then make a conditional + * request with the E-Tag and include values for all properties. + */ + properties?: string; + /** + * Optional. The owner of the blob or directory. + */ + owner?: string; + /** + * Optional. The owning group of the blob or directory. + */ + group?: string; + /** + * Optional and only valid if Hierarchical Namespace is enabled for the account. Sets POSIX + * access permissions for the file owner, the file owning group, and others. Each class may be + * granted read, write, or execute permission. The sticky bit is also supported. Both symbolic + * (rwxrw-rw-) and 4-digit octal notation (e.g. 0766) are supported. + */ + permissions?: string; + /** + * Sets POSIX access control rights on files and directories. The value is a comma-separated list + * of access control entries. Each access control entry (ACE) consists of a scope, a type, a user + * or group identifier, and permissions in the format "[scope:][type]:[id]:[permissions]". + */ + acl?: string; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value + * pairs are specified, the operation will copy the metadata from the source blob or file to the + * destination blob. If one or more name-value pairs are specified, the destination blob is + * created with the specified metadata, and metadata is not copied from the source blob or file. + * Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules + * for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more + * information. + */ + metadata?: { [propertyName: string]: string }; + /** + * Additional parameters for the operation + */ + pathHTTPHeaders?: PathHTTPHeaders; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface PathLeaseOptionalParams { + /** + * The lease duration is required to acquire a lease, and specifies the duration of the lease in + * seconds. The lease duration must be between 15 and 60 seconds or -1 for infinite lease. + */ + xMsLeaseDuration?: number; + /** + * The lease break period duration is optional to break a lease, and specifies the break period + * of the lease in seconds. The lease break duration must be between 0 and 60 seconds. + */ + xMsLeaseBreakPeriod?: number; + /** + * Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if + * the proposed lease ID is not in the correct format. See Guid Constructor (String) for a list + * of valid GUID string formats. + */ + proposedLeaseId?: string; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value + * pairs are specified, the operation will copy the metadata from the source blob or file to the + * destination blob. If one or more name-value pairs are specified, the destination blob is + * created with the specified metadata, and metadata is not copied from the source blob or file. + * Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules + * for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more + * information. + */ + metadata?: { [propertyName: string]: string }; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface PathReadOptionalParams { + /** + * Optional. When this header is set to "true" and specified together with the Range header, the + * service returns the MD5 hash for the range, as long as the range is less than or equal to 4MB + * in size. If this header is specified without the Range header, the service returns status code + * 400 (Bad Request). If this header is set to true when the range exceeds 4 MB in size, the + * service returns status code 400 (Bad Request). + */ + xMsRangeGetContentMd5?: boolean; + /** + * The snapshot parameter is an opaque DateTime value that, when present, specifies the blob + * snapshot to retrieve. For more information on working with blob snapshots, see Creating + * a Snapshot of a Blob. + */ + snapshot?: string; + /** + * The version id parameter is an opaque DateTime value that, when present, specifies the version + * of the blob to operate on. It's for service version 2019-10-10 and newer. + */ + versionId?: string; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * The HTTP Range request header specifies one or more byte ranges of the resource to be + * retrieved. + */ + range?: string; + /** + * Optional. When this header is set to "true" and specified together with the Range header, the + * service returns the MD5 hash for the range, as long as the range is less than or equal to 4MB + * in size. If this header is specified without the Range header, the service returns status code + * 400 (Bad Request). If this header is set to true when the range exceeds 4 MB in size, the + * service returns status code 400 (Bad Request). + */ + rangeGetContentMD5?: boolean; + /** + * When set to true and specified together with the Range, the service returns the CRC64 hash for + * the range, as long as the range is less than or equal to 4 MB in size. + */ + rangeGetContentCRC64?: boolean; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value + * pairs are specified, the operation will copy the metadata from the source blob or file to the + * destination blob. If one or more name-value pairs are specified, the destination blob is + * created with the specified metadata, and metadata is not copied from the source blob or file. + * Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules + * for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more + * information. + */ + metadata?: { [propertyName: string]: string }; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; + /** + * Additional parameters for the operation + */ + cpkInfo?: CpkInfo; +} + +/** + * Optional Parameters. + */ +export interface PathGetPropertiesOptionalParams { + /** + * Optional. If the value is "getStatus" only the system defined properties for the path are + * returned. If the value is "getAccessControl" the access control list is returned in the + * response headers (Hierarchical Namespace must be enabled for the account), otherwise the + * properties are returned. Possible values include: 'getAccessControl', 'getStatus' + */ + action?: PathGetPropertiesAction; + /** + * Optional. Valid only when Hierarchical Namespace is enabled for the account. If "true", the + * user identity values returned in the x-ms-owner, x-ms-group, and x-ms-acl response headers + * will be transformed from Azure Active Directory Object IDs to User Principal Names. If + * "false", the values will be returned as Azure Active Directory Object IDs. The default value + * is false. Note that group and application Object IDs are not translated because they do not + * have unique friendly names. + */ + upn?: boolean; + /** + * The snapshot parameter is an opaque DateTime value that, when present, specifies the blob + * snapshot to retrieve. For more information on working with blob snapshots, see Creating + * a Snapshot of a Blob. + */ + snapshot?: string; + /** + * The version id parameter is an opaque DateTime value that, when present, specifies the version + * of the blob to operate on. It's for service version 2019-10-10 and newer. + */ + versionId?: string; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value + * pairs are specified, the operation will copy the metadata from the source blob or file to the + * destination blob. If one or more name-value pairs are specified, the destination blob is + * created with the specified metadata, and metadata is not copied from the source blob or file. + * Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules + * for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more + * information. + */ + metadata?: { [propertyName: string]: string }; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; + /** + * Additional parameters for the operation + */ + cpkInfo?: CpkInfo; +} + +/** + * Optional Parameters. + */ +export interface PathDeleteMethodOptionalParams { + /** + * Required + */ + recursive?: boolean; + /** + * Optional. When deleting a directory, the number of paths that are deleted with each + * invocation is limited. If the number of paths to be deleted exceeds this limit, a + * continuation token is returned in this response header. When a continuation token is returned + * in the response, it must be specified in a subsequent invocation of the delete operation to + * continue deleting the directory. + */ + continuation?: string; + /** + * The snapshot parameter is an opaque DateTime value that, when present, specifies the blob + * snapshot to retrieve. For more information on working with blob snapshots, see Creating + * a Snapshot of a Blob. + */ + snapshot?: string; + /** + * The version id parameter is an opaque DateTime value that, when present, specifies the version + * of the blob to operate on. It's for service version 2019-10-10 and newer. + */ + versionId?: string; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Required if the blob has associated snapshots. Specify one of the following two options: + * include: Delete the base blob and all of its snapshots. only: Delete only the blob's snapshots + * and not the blob itself. Possible values include: 'include', 'only' + */ + deleteSnapshots?: DeleteSnapshotsOptionType; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Optional. Only possible value is 'permanent', which specifies to permanently delete a blob if + * blob soft delete is enabled. Possible values include: 'Permanent' + */ + blobDeleteType?: BlobDeleteType; + /** + * Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value + * pairs are specified, the operation will copy the metadata from the source blob or file to the + * destination blob. If one or more name-value pairs are specified, the destination blob is + * created with the specified metadata, and metadata is not copied from the source blob or file. + * Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules + * for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more + * information. + */ + metadata?: { [propertyName: string]: string }; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface PathSetAccessControlOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Optional. The owner of the blob or directory. + */ + owner?: string; + /** + * Optional. The owning group of the blob or directory. + */ + group?: string; + /** + * Optional and only valid if Hierarchical Namespace is enabled for the account. Sets POSIX + * access permissions for the file owner, the file owning group, and others. Each class may be + * granted read, write, or execute permission. The sticky bit is also supported. Both symbolic + * (rwxrw-rw-) and 4-digit octal notation (e.g. 0766) are supported. + */ + permissions?: string; + /** + * Sets POSIX access control rights on files and directories. The value is a comma-separated list + * of access control entries. Each access control entry (ACE) consists of a scope, a type, a user + * or group identifier, and permissions in the format "[scope:][type]:[id]:[permissions]". + */ + acl?: string; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface PathSetAccessControlRecursiveOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Optional. When deleting a directory, the number of paths that are deleted with each + * invocation is limited. If the number of paths to be deleted exceeds this limit, a + * continuation token is returned in this response header. When a continuation token is returned + * in the response, it must be specified in a subsequent invocation of the delete operation to + * continue deleting the directory. + */ + continuation?: string; + /** + * Optional. Valid for "SetAccessControlRecursive" operation. If set to false, the operation will + * terminate quickly on encountering user errors (4XX). If true, the operation will ignore user + * errors and proceed with the operation on other sub-entities of the directory. Continuation + * token will only be returned when forceFlag is true in case of user errors. If not set the + * default value is false for this. + */ + forceFlag?: boolean; + /** + * Optional. It specifies the maximum number of files or directories on which the acl change will + * be applied. If omitted or greater than 2,000, the request will process up to 2,000 items + */ + maxRecords?: number; + /** + * Sets POSIX access control rights on files and directories. The value is a comma-separated list + * of access control entries. Each access control entry (ACE) consists of a scope, a type, a user + * or group identifier, and permissions in the format "[scope:][type]:[id]:[permissions]". + */ + acl?: string; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; +} + +/** + * Optional Parameters. + */ +export interface PathSetPropertiesOptionalParams { + /** + * Optional. User-defined properties to be stored with the filesystem, in the format of a + * comma-separated list of name and value pairs "n1=v1, n2=v2, ...", where each value is a base64 + * encoded string. Note that the string may only contain ASCII characters in the ISO-8859-1 + * character set. If the filesystem exists, any properties not included in the list will be + * removed. All properties are removed if the header is omitted. To merge new and existing + * properties, first get all existing properties and the current E-Tag, then make a conditional + * request with the E-Tag and include values for all properties. + */ + properties?: string; + /** + * Optional and only valid if Hierarchical Namespace is enabled for the account. Sets POSIX + * access permissions for the file owner, the file owning group, and others. Each class may be + * granted read, write, or execute permission. The sticky bit is also supported. Both symbolic + * (rwxrw-rw-) and 4-digit octal notation (e.g. 0766) are supported. + */ + permissions?: string; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + pathHTTPHeaders?: PathHTTPHeaders; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface PathFlushDataOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * This parameter allows the caller to upload data in parallel and control the order in which it + * is appended to the file. It is required when uploading data to be appended to the file and + * when flushing previously uploaded data to the file. The value must be the position where the + * data is to be appended. Uploaded data is not immediately flushed, or written, to the file. + * To flush, the previously uploaded data must be contiguous, the position parameter must be + * specified and equal to the length of the file after all data has been written, and there must + * not be a request entity body included with the request. + */ + position?: number; + /** + * Valid only for flush operations. If "true", uncommitted data is retained after the flush + * operation completes; otherwise, the uncommitted data is deleted after the flush operation. + * The default is false. Data at offsets less than the specified position are written to the + * file when flush succeeds, but this optional parameter allows data after the flush position to + * be retained for a future flush operation. + */ + retainUncommittedData?: boolean; + /** + * Azure Storage Events allow applications to receive notifications when files change. When Azure + * Storage Events are enabled, a file changed event is raised. This event has a property + * indicating whether this is the final change to distinguish the difference between an + * intermediate flush to a file stream and the final close of a file stream. The close query + * parameter is valid only when the action is "flush" and change notifications are enabled. If + * the value of close is "true" and the flush operation completes successfully, the service + * raises a file change notification with a property indicating that this is the final update + * (the file stream has been closed). If "false" a change notification is raised indicating the + * file has changed. The default is false. This query parameter is set to true by the Hadoop ABFS + * driver to indicate that the file stream has been closed." + */ + close?: boolean; + /** + * Required for "Append Data" and "Flush Data". Must be 0 for "Flush Data". Must be the length + * of the request content in bytes for "Append Data". + */ + contentLength?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if + * the proposed lease ID is not in the correct format. See Guid Constructor (String) for a list + * of valid GUID string formats. + */ + proposedLeaseId?: string; + /** + * The lease duration is required to acquire a lease, and specifies the duration of the lease in + * seconds. The lease duration must be between 15 and 60 seconds or -1 for infinite lease. + */ + xMsLeaseDuration?: number; + /** + * Describes what lease action to take. Possible values include: 'acquire', 'release', 'renew', + * 'break', 'change', 'auto-renew', 'acquire-release' + */ + leaseAction?: LeaseAction; + /** + * Additional parameters for the operation + */ + pathHTTPHeaders?: PathHTTPHeaders; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; + /** + * Additional parameters for the operation + */ + cpkInfo?: CpkInfo; +} + +/** + * Optional Parameters. + */ +export interface PathAppendDataOptionalParams { + /** + * This parameter allows the caller to upload data in parallel and control the order in which it + * is appended to the file. It is required when uploading data to be appended to the file and + * when flushing previously uploaded data to the file. The value must be the position where the + * data is to be appended. Uploaded data is not immediately flushed, or written, to the file. + * To flush, the previously uploaded data must be contiguous, the position parameter must be + * specified and equal to the length of the file after all data has been written, and there must + * not be a request entity body included with the request. + */ + position?: number; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Required for "Append Data" and "Flush Data". Must be 0 for "Flush Data". Must be the length + * of the request content in bytes for "Append Data". + */ + contentLength?: number; + /** + * Specify the transactional crc64 for the body, to be validated by the service. + */ + transactionalContentCrc64?: Uint8Array; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if + * the proposed lease ID is not in the correct format. See Guid Constructor (String) for a list + * of valid GUID string formats. + */ + proposedLeaseId?: string; + /** + * The lease duration is required to acquire a lease, and specifies the duration of the lease in + * seconds. The lease duration must be between 15 and 60 seconds or -1 for infinite lease. + */ + xMsLeaseDuration?: number; + /** + * Describes what lease action to take. Possible values include: 'acquire', 'release', 'renew', + * 'break', 'change', 'auto-renew', 'acquire-release' + */ + leaseAction?: LeaseAction; + /** + * Optional. This parameter allows the caller to flush during an append call. Default value is + * 'false' , if 'true' the data will be flushed with the append call. Note that when using + * flush=true, the following headers are not supported - 'x-ms-cache-control', + * 'x-ms-content-encoding', 'x-ms-content-type', 'x-ms-content-language', 'x-ms-content-md5', + * 'x-ms-content-disposition'. To set these headers during flush, please use action=flush + */ + flush?: boolean; + /** + * Additional parameters for the operation + */ + pathHTTPHeaders?: PathHTTPHeaders; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + cpkInfo?: CpkInfo; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface PathSetExpiryOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * The time to set the blob to expiry + */ + expiresOn?: string; +} + +/** + * Optional Parameters. + */ +export interface PathUndeleteOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Only for hierarchical namespace enabled accounts. Optional. The path of the soft deleted blob + * to undelete. + */ + undeleteSource?: string; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; +} + +/** + * Optional Parameters. + */ +export interface ContainerCreateOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value + * pairs are specified, the operation will copy the metadata from the source blob or file to the + * destination blob. If one or more name-value pairs are specified, the destination blob is + * created with the specified metadata, and metadata is not copied from the source blob or file. + * Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules + * for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more + * information. + */ + metadata?: { [propertyName: string]: string }; + /** + * Specifies whether data in the container may be accessed publicly and the level of access. + * Possible values include: 'container', 'blob' + */ + access?: PublicAccessType; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + containerCpkScopeInfo?: ContainerCpkScopeInfo; +} + +/** + * Optional Parameters. + */ +export interface ContainerGetPropertiesOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface ContainerGetPropertiesWithHeadOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface ContainerDeleteMethodOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface ContainerSetMetadataOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value + * pairs are specified, the operation will copy the metadata from the source blob or file to the + * destination blob. If one or more name-value pairs are specified, the destination blob is + * created with the specified metadata, and metadata is not copied from the source blob or file. + * Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules + * for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more + * information. + */ + metadata?: { [propertyName: string]: string }; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface ContainerGetAccessPolicyOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface ContainerSetAccessPolicyOptionalParams { + /** + * the acls for the container + */ + containerAcl?: SignedIdentifier[]; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Specifies whether data in the container may be accessed publicly and the level of access. + * Possible values include: 'container', 'blob' + */ + access?: PublicAccessType; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface ContainerRestoreOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Optional. Version 2019-12-12 and later. Specifies the name of the deleted container to + * restore. + */ + deletedContainerName?: string; + /** + * Optional. Version 2019-12-12 and later. Specifies the version of the deleted container to + * restore. + */ + deletedContainerVersion?: string; +} + +/** + * Optional Parameters. + */ +export interface ContainerSubmitBatchOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; +} + +/** + * Optional Parameters. + */ +export interface ContainerFilterBlobsOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Filters the results to return only to return only blobs whose tags match the specified + * expression. + */ + where?: string; + /** + * A string value that identifies the portion of the list of containers to be returned with the + * next listing operation. The operation returns the NextMarker value within the response body if + * the listing operation did not return all containers remaining to be listed with the current + * page. The NextMarker value can be used as the value for the marker parameter in a subsequent + * call to request the next page of list items. The marker value is opaque to the client. + */ + marker?: string; + /** + * Specifies the maximum number of containers to return. If the request does not specify + * maxresults, or specifies a value greater than 5000, the server will return up to 5000 items. + * Note that if the listing operation crosses a partition boundary, then the service will return + * a continuation token for retrieving the remainder of the results. For this reason, it is + * possible that the service will return fewer results than specified by maxresults, or than the + * default of 5000. + */ + maxresults?: number; + /** + * Include this parameter to specify one or more datasets to include in the response. + */ + include?: FilterBlobsIncludeItem[]; +} + +/** + * Optional Parameters. + */ +export interface ContainerAcquireLeaseOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Specifies the duration of the lease, in seconds, or negative one (-1) for a lease that never + * expires. A non-infinite lease can be between 15 and 60 seconds. A lease duration cannot be + * changed using renew or change. + */ + duration?: number; + /** + * Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if + * the proposed lease ID is not in the correct format. See Guid Constructor (String) for a list + * of valid GUID string formats. + */ + proposedLeaseId?: string; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface ContainerReleaseLeaseOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface ContainerRenewLeaseOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface ContainerBreakLeaseOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * For a break operation, proposed duration the lease should continue before it is broken, in + * seconds, between 0 and 60. This break period is only used if it is shorter than the time + * remaining on the lease. If longer, the time remaining on the lease is used. A new lease will + * not be available before the break period has expired, but the lease may be held for longer + * than the break period. If this header does not appear with a break operation, a fixed-duration + * lease breaks after the remaining lease period elapses, and an infinite lease breaks + * immediately. + */ + breakPeriod?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface ContainerChangeLeaseOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface PageBlobCreateOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Optional. Indicates the tier to be set on the page blob. Possible values include: 'P4', 'P6', + * 'P10', 'P15', 'P20', 'P30', 'P40', 'P50', 'P60', 'P70', 'P80' + */ + tier?: PremiumPageBlobAccessTier; + /** + * Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value + * pairs are specified, the operation will copy the metadata from the source blob or file to the + * destination blob. If one or more name-value pairs are specified, the destination blob is + * created with the specified metadata, and metadata is not copied from the source blob or file. + * Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules + * for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more + * information. + */ + metadata?: { [propertyName: string]: string }; + /** + * Set for page blobs only. The sequence number is a user-controlled value that you can use to + * track requests. The value of the sequence number must be between 0 and 2^63 - 1. Default + * value: 0. + */ + blobSequenceNumber?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Optional. Used to set blob tags in various blob operations. + */ + blobTagsString?: string; + /** + * Specifies the date time when the blobs immutability policy is set to expire. + */ + immutabilityPolicyExpiry?: Date; + /** + * Specifies the immutability policy mode to set on the blob. Possible values include: 'Mutable', + * 'Unlocked', 'Locked' + */ + immutabilityPolicyMode?: BlobImmutabilityPolicyMode; + /** + * Specified if a legal hold should be set on the blob. + */ + legalHold?: boolean; + /** + * Additional parameters for the operation + */ + blobHTTPHeaders?: BlobHTTPHeaders; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + cpkInfo?: CpkInfo; + /** + * Additional parameters for the operation + */ + cpkScopeInfo?: CpkScopeInfo; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface PageBlobUploadPagesOptionalParams { + /** + * Specify the transactional md5 for the body, to be validated by the service. + */ + transactionalContentMD5?: Uint8Array; + /** + * Specify the transactional crc64 for the body, to be validated by the service. + */ + transactionalContentCrc64?: Uint8Array; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * The HTTP Range request header specifies one or more byte ranges of the resource to be + * retrieved. + */ + range?: string; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + cpkInfo?: CpkInfo; + /** + * Additional parameters for the operation + */ + cpkScopeInfo?: CpkScopeInfo; + /** + * Additional parameters for the operation + */ + sequenceNumberAccessConditions?: SequenceNumberAccessConditions; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface PageBlobClearPagesOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * The HTTP Range request header specifies one or more byte ranges of the resource to be + * retrieved. + */ + range?: string; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + cpkInfo?: CpkInfo; + /** + * Additional parameters for the operation + */ + cpkScopeInfo?: CpkScopeInfo; + /** + * Additional parameters for the operation + */ + sequenceNumberAccessConditions?: SequenceNumberAccessConditions; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface PageBlobUploadPagesFromURLOptionalParams { + /** + * Specify the md5 calculated for the range of bytes that must be read from the copy source. + */ + sourceContentMD5?: Uint8Array; + /** + * Specify the crc64 calculated for the range of bytes that must be read from the copy source. + */ + sourceContentcrc64?: Uint8Array; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Only Bearer type is supported. Credentials should be a valid OAuth access token to copy + * source. + */ + copySourceAuthorization?: string; + /** + * Additional parameters for the operation + */ + cpkInfo?: CpkInfo; + /** + * Additional parameters for the operation + */ + cpkScopeInfo?: CpkScopeInfo; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + sequenceNumberAccessConditions?: SequenceNumberAccessConditions; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; + /** + * Additional parameters for the operation + */ + sourceModifiedAccessConditions?: SourceModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface PageBlobGetPageRangesOptionalParams { + /** + * The snapshot parameter is an opaque DateTime value that, when present, specifies the blob + * snapshot to retrieve. For more information on working with blob snapshots, see Creating + * a Snapshot of a Blob. + */ + snapshot?: string; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * The HTTP Range request header specifies one or more byte ranges of the resource to be + * retrieved. + */ + range?: string; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * A string value that identifies the portion of the list of containers to be returned with the + * next listing operation. The operation returns the NextMarker value within the response body if + * the listing operation did not return all containers remaining to be listed with the current + * page. The NextMarker value can be used as the value for the marker parameter in a subsequent + * call to request the next page of list items. The marker value is opaque to the client. + */ + marker?: string; + /** + * Specifies the maximum number of containers to return. If the request does not specify + * maxresults, or specifies a value greater than 5000, the server will return up to 5000 items. + * Note that if the listing operation crosses a partition boundary, then the service will return + * a continuation token for retrieving the remainder of the results. For this reason, it is + * possible that the service will return fewer results than specified by maxresults, or than the + * default of 5000. + */ + maxresults?: number; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface PageBlobGetPageRangesDiffOptionalParams { + /** + * The snapshot parameter is an opaque DateTime value that, when present, specifies the blob + * snapshot to retrieve. For more information on working with blob snapshots, see Creating + * a Snapshot of a Blob. + */ + snapshot?: string; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Optional in version 2015-07-08 and newer. The prevsnapshot parameter is a DateTime value that + * specifies that the response will contain only pages that were changed between target blob and + * previous snapshot. Changed pages include both updated and cleared pages. The target blob may + * be a snapshot, as long as the snapshot specified by prevsnapshot is the older of the two. Note + * that incremental snapshots are currently supported only for blobs created on or after January + * 1, 2016. + */ + prevsnapshot?: string; + /** + * Optional. This header is only supported in service versions 2019-04-19 and after and specifies + * the URL of a previous snapshot of the target blob. The response will only contain pages that + * were changed between the target blob and its previous snapshot. + */ + prevSnapshotUrl?: string; + /** + * The HTTP Range request header specifies one or more byte ranges of the resource to be + * retrieved. + */ + range?: string; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * A string value that identifies the portion of the list of containers to be returned with the + * next listing operation. The operation returns the NextMarker value within the response body if + * the listing operation did not return all containers remaining to be listed with the current + * page. The NextMarker value can be used as the value for the marker parameter in a subsequent + * call to request the next page of list items. The marker value is opaque to the client. + */ + marker?: string; + /** + * Specifies the maximum number of containers to return. If the request does not specify + * maxresults, or specifies a value greater than 5000, the server will return up to 5000 items. + * Note that if the listing operation crosses a partition boundary, then the service will return + * a continuation token for retrieving the remainder of the results. For this reason, it is + * possible that the service will return fewer results than specified by maxresults, or than the + * default of 5000. + */ + maxresults?: number; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface PageBlobResizeOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + cpkInfo?: CpkInfo; + /** + * Additional parameters for the operation + */ + cpkScopeInfo?: CpkScopeInfo; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface PageBlobUpdateSequenceNumberOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Set for page blobs only. The sequence number is a user-controlled value that you can use to + * track requests. The value of the sequence number must be between 0 and 2^63 - 1. Default + * value: 0. + */ + blobSequenceNumber?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface PageBlobCopyIncrementalOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface AppendBlobCreateOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value + * pairs are specified, the operation will copy the metadata from the source blob or file to the + * destination blob. If one or more name-value pairs are specified, the destination blob is + * created with the specified metadata, and metadata is not copied from the source blob or file. + * Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules + * for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more + * information. + */ + metadata?: { [propertyName: string]: string }; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Optional. Used to set blob tags in various blob operations. + */ + blobTagsString?: string; + /** + * Specifies the date time when the blobs immutability policy is set to expire. + */ + immutabilityPolicyExpiry?: Date; + /** + * Specifies the immutability policy mode to set on the blob. Possible values include: 'Mutable', + * 'Unlocked', 'Locked' + */ + immutabilityPolicyMode?: BlobImmutabilityPolicyMode; + /** + * Specified if a legal hold should be set on the blob. + */ + legalHold?: boolean; + /** + * Additional parameters for the operation + */ + blobHTTPHeaders?: BlobHTTPHeaders; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + cpkInfo?: CpkInfo; + /** + * Additional parameters for the operation + */ + cpkScopeInfo?: CpkScopeInfo; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface AppendBlobAppendBlockOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Specify the transactional md5 for the body, to be validated by the service. + */ + transactionalContentMD5?: Uint8Array; + /** + * Specify the transactional crc64 for the body, to be validated by the service. + */ + transactionalContentCrc64?: Uint8Array; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + appendPositionAccessConditions?: AppendPositionAccessConditions; + /** + * Additional parameters for the operation + */ + cpkInfo?: CpkInfo; + /** + * Additional parameters for the operation + */ + cpkScopeInfo?: CpkScopeInfo; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface AppendBlobAppendBlockFromUrlOptionalParams { + /** + * Bytes of source data in the specified range. + */ + sourceRange?: string; + /** + * Specify the md5 calculated for the range of bytes that must be read from the copy source. + */ + sourceContentMD5?: Uint8Array; + /** + * Specify the crc64 calculated for the range of bytes that must be read from the copy source. + */ + sourceContentcrc64?: Uint8Array; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Specify the transactional md5 for the body, to be validated by the service. + */ + transactionalContentMD5?: Uint8Array; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Only Bearer type is supported. Credentials should be a valid OAuth access token to copy + * source. + */ + copySourceAuthorization?: string; + /** + * Additional parameters for the operation + */ + cpkInfo?: CpkInfo; + /** + * Additional parameters for the operation + */ + cpkScopeInfo?: CpkScopeInfo; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + appendPositionAccessConditions?: AppendPositionAccessConditions; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; + /** + * Additional parameters for the operation + */ + sourceModifiedAccessConditions?: SourceModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface AppendBlobSealOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; + /** + * Additional parameters for the operation + */ + appendPositionAccessConditions?: AppendPositionAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface BlockBlobUploadOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Specify the transactional md5 for the body, to be validated by the service. + */ + transactionalContentMD5?: Uint8Array; + /** + * Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value + * pairs are specified, the operation will copy the metadata from the source blob or file to the + * destination blob. If one or more name-value pairs are specified, the destination blob is + * created with the specified metadata, and metadata is not copied from the source blob or file. + * Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules + * for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more + * information. + */ + metadata?: { [propertyName: string]: string }; + /** + * Optional. Indicates the tier to be set on the blob. Possible values include: 'P4', 'P6', + * 'P10', 'P15', 'P20', 'P30', 'P40', 'P50', 'P60', 'P70', 'P80', 'Hot', 'Cool', 'Archive', + * 'Premium' + */ + tier?: AccessTier; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Optional. Used to set blob tags in various blob operations. + */ + blobTagsString?: string; + /** + * Specifies the date time when the blobs immutability policy is set to expire. + */ + immutabilityPolicyExpiry?: Date; + /** + * Specifies the immutability policy mode to set on the blob. Possible values include: 'Mutable', + * 'Unlocked', 'Locked' + */ + immutabilityPolicyMode?: BlobImmutabilityPolicyMode; + /** + * Specified if a legal hold should be set on the blob. + */ + legalHold?: boolean; + /** + * Specify the transactional crc64 for the body, to be validated by the service. + */ + transactionalContentCrc64?: Uint8Array; + /** + * Additional parameters for the operation + */ + blobHTTPHeaders?: BlobHTTPHeaders; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + cpkInfo?: CpkInfo; + /** + * Additional parameters for the operation + */ + cpkScopeInfo?: CpkScopeInfo; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface BlockBlobPutBlobFromUrlOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Specify the transactional md5 for the body, to be validated by the service. + */ + transactionalContentMD5?: Uint8Array; + /** + * Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value + * pairs are specified, the operation will copy the metadata from the source blob or file to the + * destination blob. If one or more name-value pairs are specified, the destination blob is + * created with the specified metadata, and metadata is not copied from the source blob or file. + * Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules + * for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more + * information. + */ + metadata?: { [propertyName: string]: string }; + /** + * Optional. Indicates the tier to be set on the blob. Possible values include: 'P4', 'P6', + * 'P10', 'P15', 'P20', 'P30', 'P40', 'P50', 'P60', 'P70', 'P80', 'Hot', 'Cool', 'Archive', + * 'Premium' + */ + tier?: AccessTier; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Specify the md5 calculated for the range of bytes that must be read from the copy source. + */ + sourceContentMD5?: Uint8Array; + /** + * Optional. Used to set blob tags in various blob operations. + */ + blobTagsString?: string; + /** + * Optional, default is true. Indicates if properties from the source blob should be copied. + */ + copySourceBlobProperties?: boolean; + /** + * Only Bearer type is supported. Credentials should be a valid OAuth access token to copy + * source. + */ + copySourceAuthorization?: string; + /** + * Optional, default 'replace'. Indicates if source tags should be copied or replaced with the + * tags specified by x-ms-tags. Possible values include: 'REPLACE', 'COPY' + */ + copySourceTags?: BlobCopySourceTags; + /** + * Additional parameters for the operation + */ + blobHTTPHeaders?: BlobHTTPHeaders; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + cpkInfo?: CpkInfo; + /** + * Additional parameters for the operation + */ + cpkScopeInfo?: CpkScopeInfo; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; + /** + * Additional parameters for the operation + */ + sourceModifiedAccessConditions?: SourceModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface BlockBlobStageBlockOptionalParams { + /** + * Specify the transactional md5 for the body, to be validated by the service. + */ + transactionalContentMD5?: Uint8Array; + /** + * Specify the transactional crc64 for the body, to be validated by the service. + */ + transactionalContentCrc64?: Uint8Array; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + cpkInfo?: CpkInfo; + /** + * Additional parameters for the operation + */ + cpkScopeInfo?: CpkScopeInfo; +} + +/** + * Optional Parameters. + */ +export interface BlockBlobStageBlockFromURLOptionalParams { + /** + * Bytes of source data in the specified range. + */ + sourceRange?: string; + /** + * Specify the md5 calculated for the range of bytes that must be read from the copy source. + */ + sourceContentMD5?: Uint8Array; + /** + * Specify the crc64 calculated for the range of bytes that must be read from the copy source. + */ + sourceContentcrc64?: Uint8Array; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Only Bearer type is supported. Credentials should be a valid OAuth access token to copy + * source. + */ + copySourceAuthorization?: string; + /** + * Additional parameters for the operation + */ + cpkInfo?: CpkInfo; + /** + * Additional parameters for the operation + */ + cpkScopeInfo?: CpkScopeInfo; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + sourceModifiedAccessConditions?: SourceModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface BlockBlobCommitBlockListOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Specify the transactional md5 for the body, to be validated by the service. + */ + transactionalContentMD5?: Uint8Array; + /** + * Specify the transactional crc64 for the body, to be validated by the service. + */ + transactionalContentCrc64?: Uint8Array; + /** + * Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value + * pairs are specified, the operation will copy the metadata from the source blob or file to the + * destination blob. If one or more name-value pairs are specified, the destination blob is + * created with the specified metadata, and metadata is not copied from the source blob or file. + * Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules + * for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more + * information. + */ + metadata?: { [propertyName: string]: string }; + /** + * Optional. Indicates the tier to be set on the blob. Possible values include: 'P4', 'P6', + * 'P10', 'P15', 'P20', 'P30', 'P40', 'P50', 'P60', 'P70', 'P80', 'Hot', 'Cool', 'Archive', + * 'Premium' + */ + tier?: AccessTier; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Optional. Used to set blob tags in various blob operations. + */ + blobTagsString?: string; + /** + * Specifies the date time when the blobs immutability policy is set to expire. + */ + immutabilityPolicyExpiry?: Date; + /** + * Specifies the immutability policy mode to set on the blob. Possible values include: 'Mutable', + * 'Unlocked', 'Locked' + */ + immutabilityPolicyMode?: BlobImmutabilityPolicyMode; + /** + * Specified if a legal hold should be set on the blob. + */ + legalHold?: boolean; + /** + * Additional parameters for the operation + */ + blobHTTPHeaders?: BlobHTTPHeaders; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + cpkInfo?: CpkInfo; + /** + * Additional parameters for the operation + */ + cpkScopeInfo?: CpkScopeInfo; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface BlockBlobGetBlockListOptionalParams { + /** + * The snapshot parameter is an opaque DateTime value that, when present, specifies the blob + * snapshot to retrieve. For more information on working with blob snapshots, see Creating + * a Snapshot of a Blob. + */ + snapshot?: string; + /** + * Specifies whether to return the list of committed blocks, the list of uncommitted blocks, or + * both lists together. Possible values include: 'committed', 'uncommitted', 'all'. Default + * value: 'committed'. + */ + listType?: BlockListType; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface BlobUndeleteOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; +} + +/** + * Optional Parameters. + */ +export interface BlobSetExpiryOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * The time to set the blob to expiry + */ + expiresOn?: string; +} + +/** + * Optional Parameters. + */ +export interface BlobSetHTTPHeadersOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + blobHTTPHeaders?: BlobHTTPHeaders; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface BlobSetImmutabilityPolicyOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Specifies the date time when the blobs immutability policy is set to expire. + */ + immutabilityPolicyExpiry?: Date; + /** + * Specifies the immutability policy mode to set on the blob. Possible values include: 'Mutable', + * 'Unlocked', 'Locked' + */ + immutabilityPolicyMode?: BlobImmutabilityPolicyMode; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface BlobDeleteImmutabilityPolicyOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; +} + +/** + * Optional Parameters. + */ +export interface BlobSetLegalHoldOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; +} + +/** + * Optional Parameters. + */ +export interface BlobSetMetadataOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value + * pairs are specified, the operation will copy the metadata from the source blob or file to the + * destination blob. If one or more name-value pairs are specified, the destination blob is + * created with the specified metadata, and metadata is not copied from the source blob or file. + * Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules + * for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more + * information. + */ + metadata?: { [propertyName: string]: string }; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + cpkInfo?: CpkInfo; + /** + * Additional parameters for the operation + */ + cpkScopeInfo?: CpkScopeInfo; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface BlobAcquireLeaseOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Specifies the duration of the lease, in seconds, or negative one (-1) for a lease that never + * expires. A non-infinite lease can be between 15 and 60 seconds. A lease duration cannot be + * changed using renew or change. + */ + duration?: number; + /** + * Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if + * the proposed lease ID is not in the correct format. See Guid Constructor (String) for a list + * of valid GUID string formats. + */ + proposedLeaseId?: string; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface BlobReleaseLeaseOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface BlobRenewLeaseOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface BlobChangeLeaseOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface BlobBreakLeaseOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * For a break operation, proposed duration the lease should continue before it is broken, in + * seconds, between 0 and 60. This break period is only used if it is shorter than the time + * remaining on the lease. If longer, the time remaining on the lease is used. A new lease will + * not be available before the break period has expired, but the lease may be held for longer + * than the break period. If this header does not appear with a break operation, a fixed-duration + * lease breaks after the remaining lease period elapses, and an infinite lease breaks + * immediately. + */ + breakPeriod?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface BlobCreateSnapshotOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value + * pairs are specified, the operation will copy the metadata from the source blob or file to the + * destination blob. If one or more name-value pairs are specified, the destination blob is + * created with the specified metadata, and metadata is not copied from the source blob or file. + * Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules + * for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more + * information. + */ + metadata?: { [propertyName: string]: string }; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + cpkInfo?: CpkInfo; + /** + * Additional parameters for the operation + */ + cpkScopeInfo?: CpkScopeInfo; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface BlobStartCopyFromURLOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value + * pairs are specified, the operation will copy the metadata from the source blob or file to the + * destination blob. If one or more name-value pairs are specified, the destination blob is + * created with the specified metadata, and metadata is not copied from the source blob or file. + * Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules + * for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more + * information. + */ + metadata?: { [propertyName: string]: string }; + /** + * Optional. Indicates the tier to be set on the blob. Possible values include: 'P4', 'P6', + * 'P10', 'P15', 'P20', 'P30', 'P40', 'P50', 'P60', 'P70', 'P80', 'Hot', 'Cool', 'Archive', + * 'Premium' + */ + tier?: AccessTier; + /** + * Optional: Indicates the priority with which to rehydrate an archived blob. Possible values + * include: 'High', 'Standard' + */ + rehydratePriority?: RehydratePriority; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Optional. Used to set blob tags in various blob operations. + */ + blobTagsString?: string; + /** + * Overrides the sealed state of the destination blob. Service version 2019-12-12 and newer. + */ + sealBlob?: boolean; + /** + * Specifies the date time when the blobs immutability policy is set to expire. + */ + immutabilityPolicyExpiry?: Date; + /** + * Specifies the immutability policy mode to set on the blob. Possible values include: 'Mutable', + * 'Unlocked', 'Locked' + */ + immutabilityPolicyMode?: BlobImmutabilityPolicyMode; + /** + * Specified if a legal hold should be set on the blob. + */ + legalHold?: boolean; + /** + * Additional parameters for the operation + */ + sourceModifiedAccessConditions?: SourceModifiedAccessConditions; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface BlobCopyFromURLOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value + * pairs are specified, the operation will copy the metadata from the source blob or file to the + * destination blob. If one or more name-value pairs are specified, the destination blob is + * created with the specified metadata, and metadata is not copied from the source blob or file. + * Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules + * for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more + * information. + */ + metadata?: { [propertyName: string]: string }; + /** + * Optional. Indicates the tier to be set on the blob. Possible values include: 'P4', 'P6', + * 'P10', 'P15', 'P20', 'P30', 'P40', 'P50', 'P60', 'P70', 'P80', 'Hot', 'Cool', 'Archive', + * 'Premium' + */ + tier?: AccessTier; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Specify the md5 calculated for the range of bytes that must be read from the copy source. + */ + sourceContentMD5?: Uint8Array; + /** + * Optional. Used to set blob tags in various blob operations. + */ + blobTagsString?: string; + /** + * Specifies the date time when the blobs immutability policy is set to expire. + */ + immutabilityPolicyExpiry?: Date; + /** + * Specifies the immutability policy mode to set on the blob. Possible values include: 'Mutable', + * 'Unlocked', 'Locked' + */ + immutabilityPolicyMode?: BlobImmutabilityPolicyMode; + /** + * Specified if a legal hold should be set on the blob. + */ + legalHold?: boolean; + /** + * Only Bearer type is supported. Credentials should be a valid OAuth access token to copy + * source. + */ + copySourceAuthorization?: string; + /** + * Optional, default 'replace'. Indicates if source tags should be copied or replaced with the + * tags specified by x-ms-tags. Possible values include: 'REPLACE', 'COPY' + */ + copySourceTags?: BlobCopySourceTags; + /** + * Additional parameters for the operation + */ + sourceModifiedAccessConditions?: SourceModifiedAccessConditions; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + cpkScopeInfo?: CpkScopeInfo; +} + +/** + * Optional Parameters. + */ +export interface BlobAbortCopyFromURLOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface BlobSetTierOptionalParams { + /** + * The snapshot parameter is an opaque DateTime value that, when present, specifies the blob + * snapshot to retrieve. For more information on working with blob snapshots, see Creating + * a Snapshot of a Blob. + */ + snapshot?: string; + /** + * The version id parameter is an opaque DateTime value that, when present, specifies the version + * of the blob to operate on. It's for service version 2019-10-10 and newer. + */ + versionId?: string; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Optional: Indicates the priority with which to rehydrate an archived blob. Possible values + * include: 'High', 'Standard' + */ + rehydratePriority?: RehydratePriority; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface BlobQueryOptionalParams { + /** + * the query request + */ + queryRequest?: QueryRequest; + /** + * The snapshot parameter is an opaque DateTime value that, when present, specifies the blob + * snapshot to retrieve. For more information on working with blob snapshots, see Creating + * a Snapshot of a Blob. + */ + snapshot?: string; + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; + /** + * Additional parameters for the operation + */ + cpkInfo?: CpkInfo; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface BlobGetTagsOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * The snapshot parameter is an opaque DateTime value that, when present, specifies the blob + * snapshot to retrieve. For more information on working with blob snapshots, see Creating + * a Snapshot of a Blob. + */ + snapshot?: string; + /** + * The version id parameter is an opaque DateTime value that, when present, specifies the version + * of the blob to operate on. It's for service version 2019-10-10 and newer. + */ + versionId?: string; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; +} + +/** + * Optional Parameters. + */ +export interface BlobSetTagsOptionalParams { + /** + * The timeout parameter is expressed in seconds. For more information, see Setting + * Timeouts for Blob Service Operations. + */ + timeout?: number; + /** + * The version id parameter is an opaque DateTime value that, when present, specifies the version + * of the blob to operate on. It's for service version 2019-10-10 and newer. + */ + versionId?: string; + /** + * Specify the transactional md5 for the body, to be validated by the service. + */ + transactionalContentMD5?: Uint8Array; + /** + * Specify the transactional crc64 for the body, to be validated by the service. + */ + transactionalContentCrc64?: Uint8Array; + /** + * Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the + * analytics logs when storage analytics logging is enabled. + */ + requestId?: string; + /** + * Blob tags + */ + tags?: BlobTags; + /** + * Additional parameters for the operation + */ + modifiedAccessConditions?: ModifiedAccessConditions; + /** + * Additional parameters for the operation + */ + leaseAccessConditions?: LeaseAccessConditions; +} + +/** + * Defines headers for ListFileSystems operation. + */ +export interface ServiceListFileSystemsHeaders { + /** + * A UTC date/time value generated by the service that indicates the time at which the response + * was initiated. + */ + date?: Date; + /** + * A server-generated UUID recorded in the analytics logs for troubleshooting and correlation. + */ + requestId?: string; + /** + * The version of the REST protocol used to process the request. + */ + version?: string; + /** + * If the number of filesystems to be listed exceeds the maxResults limit, a continuation token + * is returned in this response header. When a continuation token is returned in the response, + * it must be specified in a subsequent invocation of the list operation to continue listing the + * filesystems. + */ + continuation?: string; + /** + * The content type of list filesystem response. The default content type is application/json. + */ + contentType?: string; + errorCode?: string; +} + +/** + * Defines headers for Create operation. + */ +export interface FileSystemCreateHeaders { + /** + * A UTC date/time value generated by the service that indicates the time at which the response + * was initiated. + */ + date?: Date; + /** + * An HTTP entity tag associated with the FileSystem. + */ + eTag?: string; + /** + * The data and time the filesystem was last modified. Operations on files and directories do + * not affect the last modified time. + */ + lastModified?: Date; + /** + * A server-generated UUID recorded in the analytics logs for troubleshooting and correlation. + */ + clientRequestId?: string; + /** + * The version of the REST protocol used to process the request. + */ + version?: string; + /** + * A bool string indicates whether the namespace feature is enabled. If "true", the namespace is + * enabled for the filesystem. + */ + namespaceEnabled?: string; + errorCode?: string; +} + +/** + * Defines headers for SetProperties operation. + */ +export interface FileSystemSetPropertiesHeaders { + /** + * A UTC date/time value generated by the service that indicates the time at which the response + * was initiated. + */ + date?: Date; + /** + * An HTTP entity tag associated with the filesystem. Changes to filesystem properties affect + * the entity tag, but operations on files and directories do not. + */ + eTag?: string; + /** + * The data and time the filesystem was last modified. Changes to filesystem properties update + * the last modified time, but operations on files and directories do not. + */ + lastModified?: Date; + /** + * A server-generated UUID recorded in the analytics logs for troubleshooting and correlation. + */ + requestId?: string; + /** + * The version of the REST protocol used to process the request. + */ + version?: string; + errorCode?: string; +} + +/** + * Defines headers for GetProperties operation. + */ +export interface FileSystemGetPropertiesHeaders { + /** + * A UTC date/time value generated by the service that indicates the time at which the response + * was initiated. + */ + date?: Date; + /** + * An HTTP entity tag associated with the filesystem. Changes to filesystem properties affect + * the entity tag, but operations on files and directories do not. + */ + eTag?: string; + /** + * The data and time the filesystem was last modified. Changes to filesystem properties update + * the last modified time, but operations on files and directories do not. + */ + lastModified?: Date; + /** + * A server-generated UUID recorded in the analytics logs for troubleshooting and correlation. + */ + requestId?: string; + /** + * The version of the REST protocol used to process the request. + */ + version?: string; + /** + * The user-defined properties associated with the filesystem. A comma-separated list of name + * and value pairs in the format "n1=v1, n2=v2, ...", where each value is a base64 encoded + * string. Note that the string may only contain ASCII characters in the ISO-8859-1 character + * set. + */ + properties?: string; + /** + * A bool string indicates whether the namespace feature is enabled. If "true", the namespace is + * enabled for the filesystem. + */ + namespaceEnabled?: string; + errorCode?: string; +} + +/** + * Defines headers for Delete operation. + */ +export interface FileSystemDeleteHeaders { + /** + * A server-generated UUID recorded in the analytics logs for troubleshooting and correlation. + */ + requestId?: string; + /** + * The version of the REST protocol used to process the request. + */ + version?: string; + /** + * A UTC date/time value generated by the service that indicates the time at which the response + * was initiated. + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for ListPaths operation. + */ +export interface FileSystemListPathsHeaders { + /** + * A UTC date/time value generated by the service that indicates the time at which the response + * was initiated. + */ + date?: Date; + /** + * An HTTP entity tag associated with the filesystem. Changes to filesystem properties affect + * the entity tag, but operations on files and directories do not. + */ + eTag?: string; + /** + * The data and time the filesystem was last modified. Changes to filesystem properties update + * the last modified time, but operations on files and directories do not. + */ + lastModified?: Date; + /** + * A server-generated UUID recorded in the analytics logs for troubleshooting and correlation. + */ + requestId?: string; + /** + * The version of the REST protocol used to process the request. + */ + version?: string; + /** + * If the number of paths to be listed exceeds the maxResults limit, a continuation token is + * returned in this response header. When a continuation token is returned in the response, it + * must be specified in a subsequent invocation of the list operation to continue listing the + * paths. + */ + continuation?: string; + errorCode?: string; +} + +/** + * Defines headers for ListBlobFlatSegment operation. + */ +export interface FileSystemListBlobFlatSegmentHeaders { + /** + * The media type of the body of the response. For List Blobs this is 'application/xml' + */ + contentType?: string; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for ListBlobHierarchySegment operation. + */ +export interface FileSystemListBlobHierarchySegmentHeaders { + /** + * The media type of the body of the response. For List Blobs this is 'application/xml' + */ + contentType?: string; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for Create operation. + */ +export interface PathCreateHeaders { + /** + * A UTC date/time value generated by the service that indicates the time at which the response + * was initiated. + */ + date?: Date; + /** + * An HTTP entity tag associated with the file or directory. + */ + eTag?: string; + /** + * The data and time the file or directory was last modified. Write operations on the file or + * directory update the last modified time. + */ + lastModified?: Date; + /** + * A server-generated UUID recorded in the analytics logs for troubleshooting and correlation. + */ + requestId?: string; + /** + * The version of the REST protocol used to process the request. + */ + version?: string; + /** + * When renaming a directory, the number of paths that are renamed with each invocation is + * limited. If the number of paths to be renamed exceeds this limit, a continuation token is + * returned in this response header. When a continuation token is returned in the response, it + * must be specified in a subsequent invocation of the rename operation to continue renaming the + * directory. + */ + continuation?: string; + /** + * The size of the resource in bytes. + */ + contentLength?: number; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + isServerEncrypted?: boolean; + /** + * The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned + * when the blob was encrypted with a customer-provided key. + */ + encryptionKeySha256?: string; + errorCode?: string; +} + +/** + * Defines headers for Update operation. + */ +export interface PathUpdateHeaders { + /** + * A UTC date/time value generated by the service that indicates the time at which the response + * was initiated. + */ + date?: Date; + /** + * An HTTP entity tag associated with the file or directory. + */ + eTag?: string; + /** + * The data and time the file or directory was last modified. Write operations on the file or + * directory update the last modified time. + */ + lastModified?: Date; + /** + * Indicates that the service supports requests for partial file content. + */ + acceptRanges?: string; + /** + * If the Cache-Control request header has previously been set for the resource, that value is + * returned in this header. + */ + cacheControl?: string; + /** + * If the Content-Disposition request header has previously been set for the resource, that value + * is returned in this header. + */ + contentDisposition?: string; + /** + * If the Content-Encoding request header has previously been set for the resource, that value is + * returned in this header. + */ + contentEncoding?: string; + /** + * If the Content-Language request header has previously been set for the resource, that value is + * returned in this header. + */ + contentLanguage?: string; + /** + * The size of the resource in bytes. + */ + contentLength?: number; + /** + * Indicates the range of bytes returned in the event that the client requested a subset of the + * file by setting the Range request header. + */ + contentRange?: string; + /** + * The content type specified for the resource. If no content type was specified, the default + * content type is application/octet-stream. + */ + contentType?: string; + /** + * An MD5 hash of the request content. This header is only returned for "Append" operation. This + * header is returned so that the client can check for message content integrity. The value of + * this header is computed by the service; it is not necessarily the same value specified in the + * request headers. + */ + contentMD5?: Uint8Array; + /** + * User-defined properties associated with the file or directory, in the format of a + * comma-separated list of name and value pairs "n1=v1, n2=v2, ...", where each value is a base64 + * encoded string. Note that the string may only contain ASCII characters in the ISO-8859-1 + * character set. + */ + properties?: string; + /** + * When performing setAccessControlRecursive on a directory, the number of paths that are + * processed with each invocation is limited. If the number of paths to be processed exceeds + * this limit, a continuation token is returned in this response header. When a continuation + * token is returned in the response, it must be specified in a subsequent invocation of the + * setAccessControlRecursive operation to continue the setAccessControlRecursive operation on the + * directory. + */ + xMsContinuation?: string; + /** + * A server-generated UUID recorded in the analytics logs for troubleshooting and correlation. + */ + requestId?: string; + /** + * The version of the REST protocol used to process the request. + */ + version?: string; + errorCode?: string; +} + +/** + * Defines headers for Lease operation. + */ +export interface PathLeaseHeaders { + /** + * A UTC date/time value generated by the service that indicates the time at which the response + * was initiated. + */ + date?: Date; + /** + * An HTTP entity tag associated with the file or directory. + */ + eTag?: string; + /** + * The data and time the file or directory was last modified. Write operations on the file or + * directory update the last modified time. + */ + lastModified?: Date; + /** + * A server-generated UUID recorded in the analytics logs for troubleshooting and correlation. + */ + requestId?: string; + /** + * The version of the REST protocol used to process the request. + */ + version?: string; + /** + * A successful "acquire" action returns the lease ID. + */ + leaseId?: string; + /** + * The time remaining in the lease period in seconds. + */ + leaseTime?: string; + errorCode?: string; +} + +/** + * Defines headers for Read operation. + */ +export interface PathReadHeaders { + /** + * Indicates that the service supports requests for partial file content. + */ + acceptRanges?: string; + /** + * If the Cache-Control request header has previously been set for the resource, that value is + * returned in this header. + */ + cacheControl?: string; + /** + * If the Content-Disposition request header has previously been set for the resource, that value + * is returned in this header. + */ + contentDisposition?: string; + /** + * If the Content-Encoding request header has previously been set for the resource, that value is + * returned in this header. + */ + contentEncoding?: string; + /** + * If the Content-Language request header has previously been set for the resource, that value is + * returned in this header. + */ + contentLanguage?: string; + /** + * The size of the resource in bytes. + */ + contentLength?: number; + /** + * Indicates the range of bytes returned in the event that the client requested a subset of the + * file by setting the Range request header. + */ + contentRange?: string; + /** + * The content type specified for the resource. If no content type was specified, the default + * content type is application/octet-stream. + */ + contentType?: string; + /** + * The MD5 hash of read range. If the request is to read a specified range and the + * "x-ms-range-get-content-md5" is set to true, then the request returns an MD5 hash for the + * range, as long as the range size is less than or equal to 4 MB. + */ + contentMD5?: Uint8Array; + /** + * A UTC date/time value generated by the service that indicates the time at which the response + * was initiated. + */ + date?: Date; + /** + * An HTTP entity tag associated with the file or directory. + */ + eTag?: string; + /** + * The data and time the file or directory was last modified. Write operations on the file or + * directory update the last modified time. + */ + lastModified?: Date; + /** + * A server-generated UUID recorded in the analytics logs for troubleshooting and correlation. + */ + requestId?: string; + /** + * The version of the REST protocol used to process the request. + */ + version?: string; + /** + * The type of the resource. The value may be "file" or "directory". If not set, the value is + * "file". + */ + resourceType?: string; + /** + * The user-defined properties associated with the file or directory, in the format of a + * comma-separated list of name and value pairs "n1=v1, n2=v2, ...", where each value is a base64 + * encoded string. Note that the string may only contain ASCII characters in the ISO-8859-1 + * character set. + */ + properties?: string; + /** + * When a resource is leased, specifies whether the lease is of infinite or fixed duration. + * Possible values include: 'infinite', 'fixed' + */ + leaseDuration?: LeaseDurationType; + /** + * Lease state of the resource. Possible values include: 'available', 'leased', 'expired', + * 'breaking', 'broken' + */ + leaseState?: LeaseStateType; + /** + * The lease status of the resource. Possible values include: 'locked', 'unlocked' + */ + leaseStatus?: LeaseStatusType; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + isServerEncrypted?: boolean; + /** + * The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned + * when the blob was encrypted with a customer-provided key. + */ + encryptionKeySha256?: string; + metadata?: { [propertyName: string]: string }; + /** + * Returns the date and time the blob was created. + */ + creationTime?: Date; + /** + * Optional. Only valid when Object Replication is enabled for the storage container and on the + * destination blob of the replication. + */ + objectReplicationPolicyId?: string; + objectReplicationRules?: { [propertyName: string]: string }; + /** + * The current sequence number for a page blob. This header is not returned for block blobs or + * append blobs + */ + blobSequenceNumber?: number; + /** + * The blob's type. Possible values include: 'BlockBlob', 'PageBlob', 'AppendBlob' + */ + blobType?: BlobType; + /** + * Conclusion time of the last attempted Copy Blob operation where this blob was the destination + * blob. This value can specify the time of a completed, aborted, or failed copy attempt. This + * header does not appear if a copy is pending, if this blob has never been the destination in a + * Copy Blob operation, or if this blob has been modified after a concluded Copy Blob operation + * using Set Blob Properties, Put Blob, or Put Block List. + */ + copyCompletionTime?: Date; + /** + * Only appears when x-ms-copy-status is failed or pending. Describes the cause of the last fatal + * or non-fatal copy operation failure. This header does not appear if this blob has never been + * the destination in a Copy Blob operation, or if this blob has been modified after a concluded + * Copy Blob operation using Set Blob Properties, Put Blob, or Put Block List + */ + copyStatusDescription?: string; + /** + * String identifier for this copy operation. Use with Get Blob Properties to check the status of + * this copy operation, or pass to Abort Copy Blob to abort a pending copy. + */ + copyId?: string; + /** + * Contains the number of bytes copied and the total bytes in the source in the last attempted + * Copy Blob operation where this blob was the destination blob. Can show between 0 and + * Content-Length bytes copied. This header does not appear if this blob has never been the + * destination in a Copy Blob operation, or if this blob has been modified after a concluded Copy + * Blob operation using Set Blob Properties, Put Blob, or Put Block List + */ + copyProgress?: string; + /** + * URL up to 2 KB in length that specifies the source blob or file used in the last attempted + * Copy Blob operation where this blob was the destination blob. This header does not appear if + * this blob has never been the destination in a Copy Blob operation, or if this blob has been + * modified after a concluded Copy Blob operation using Set Blob Properties, Put Blob, or Put + * Block List. + */ + copySource?: string; + /** + * State of the copy operation identified by x-ms-copy-id. Possible values include: 'pending', + * 'success', 'aborted', 'failed' + */ + copyStatus?: CopyStatusType; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * A DateTime value returned by the service that uniquely identifies the blob. The value of this + * header indicates the blob version, and may be used in subsequent requests to access this + * version of the blob. + */ + versionId?: string; + /** + * The value of this header indicates whether version of this blob is a current version, see also + * x-ms-version-id header. + */ + isCurrentVersion?: boolean; + /** + * The number of committed blocks present in the blob. This header is returned only for append + * blobs. + */ + blobCommittedBlockCount?: number; + /** + * Returns the name of the encryption scope used to encrypt the blob contents and application + * metadata. Note that the absence of this header implies use of the default account encryption + * scope. + */ + encryptionScope?: string; + /** + * If the blob has a MD5 hash, and if request contains range header (Range or x-ms-range), this + * response header is returned with the value of the whole blob's MD5 value. This value may or + * may not be equal to the value returned in Content-MD5 header, with the latter calculated from + * the requested range + */ + blobContentMD5?: Uint8Array; + /** + * The number of tags associated with the blob + */ + tagCount?: number; + /** + * If this blob has been sealed + */ + isSealed?: boolean; + /** + * UTC date/time value generated by the service that indicates the time at which the blob was + * last read or written to + */ + lastAccessed?: Date; + /** + * UTC date/time value generated by the service that indicates the time at which the blob + * immutability policy will expire. + */ + immutabilityPolicyExpiresOn?: Date; + /** + * Indicates immutability policy mode. + */ + immutabilityPolicyMode?: string; + /** + * Indicates if a legal hold is present on the blob. + */ + legalHold?: boolean; + /** + * The MD5 hash of complete file stored in storage. If the file has a MD5 hash, and if request + * contains range header (Range or x-ms-range), this response header is returned with the value + * of the complete file's MD5 value. This value may or may not be equal to the value returned in + * Content-MD5 header, with the latter calculated from the requested range. + */ + xMsContentMd5?: Uint8Array; + /** + * If the request is to read a specified range and the x-ms-range-get-content-crc64 is set to + * true, then the request returns a crc64 for the range, as long as the range size is less than + * or equal to 4 MB. If both x-ms-range-get-content-crc64 & x-ms-range-get-content-md5 is + * specified in the same request, it will fail with 400(Bad Request) + */ + contentCrc64?: Uint8Array; + errorCode?: string; +} + +/** + * Defines headers for GetProperties operation. + */ +export interface PathGetPropertiesHeaders { + /** + * Indicates that the service supports requests for partial file content. + */ + acceptRanges?: string; + /** + * If the Cache-Control request header has previously been set for the resource, that value is + * returned in this header. + */ + cacheControl?: string; + /** + * If the Content-Disposition request header has previously been set for the resource, that value + * is returned in this header. + */ + contentDisposition?: string; + /** + * If the Content-Encoding request header has previously been set for the resource, that value is + * returned in this header. + */ + contentEncoding?: string; + /** + * If the Content-Language request header has previously been set for the resource, that value is + * returned in this header. + */ + contentLanguage?: string; + /** + * The size of the resource in bytes. + */ + contentLength?: number; + /** + * Indicates the range of bytes returned in the event that the client requested a subset of the + * file by setting the Range request header. + */ + contentRange?: string; + /** + * The content type specified for the resource. If no content type was specified, the default + * content type is application/octet-stream. + */ + contentType?: string; + /** + * The MD5 hash of complete file stored in storage. This header is returned only for + * "GetProperties" operation. If the Content-MD5 header has been set for the file, this response + * header is returned for GetProperties call so that the client can check for message content + * integrity. + */ + contentMD5?: Uint8Array; + /** + * A UTC date/time value generated by the service that indicates the time at which the response + * was initiated. + */ + date?: Date; + /** + * An HTTP entity tag associated with the file or directory. + */ + eTag?: string; + /** + * The data and time the file or directory was last modified. Write operations on the file or + * directory update the last modified time. + */ + lastModified?: Date; + /** + * A server-generated UUID recorded in the analytics logs for troubleshooting and correlation. + */ + requestId?: string; + /** + * The version of the REST protocol used to process the request. + */ + version?: string; + /** + * The type of the resource. The value may be "file" or "directory". If not set, the value is + * "file". + */ + resourceType?: string; + /** + * The user-defined properties associated with the file or directory, in the format of a + * comma-separated list of name and value pairs "n1=v1, n2=v2, ...", where each value is a base64 + * encoded string. Note that the string may only contain ASCII characters in the ISO-8859-1 + * character set. + */ + properties?: string; + /** + * The owner of the file or directory. Included in the response if Hierarchical Namespace is + * enabled for the account. + */ + owner?: string; + /** + * The owning group of the file or directory. Included in the response if Hierarchical Namespace + * is enabled for the account. + */ + group?: string; + /** + * The POSIX access permissions for the file owner, the file owning group, and others. Included + * in the response if Hierarchical Namespace is enabled for the account. + */ + permissions?: string; + /** + * The POSIX access control list for the file or directory. Included in the response only if the + * action is "getAccessControl" and Hierarchical Namespace is enabled for the account. + */ + aCL?: string; + /** + * When a resource is leased, specifies whether the lease is of infinite or fixed duration. + * Possible values include: 'infinite', 'fixed' + */ + leaseDuration?: LeaseDurationType; + /** + * Lease state of the resource. Possible values include: 'available', 'leased', 'expired', + * 'breaking', 'broken' + */ + leaseState?: LeaseStateType; + /** + * The lease status of the resource. Possible values include: 'locked', 'unlocked' + */ + leaseStatus?: LeaseStatusType; + metadata?: { [propertyName: string]: string }; + /** + * Returns the date and time the blob was created. + */ + creationTime?: Date; + /** + * Optional. Only valid when Object Replication is enabled for the storage container and on the + * destination blob of the replication. + */ + objectReplicationPolicyId?: string; + objectReplicationRules?: { [propertyName: string]: string }; + /** + * The blob's type. Possible values include: 'BlockBlob', 'PageBlob', 'AppendBlob' + */ + blobType?: BlobType; + /** + * Conclusion time of the last attempted Copy Blob operation where this blob was the destination + * blob. This value can specify the time of a completed, aborted, or failed copy attempt. This + * header does not appear if a copy is pending, if this blob has never been the destination in a + * Copy Blob operation, or if this blob has been modified after a concluded Copy Blob operation + * using Set Blob Properties, Put Blob, or Put Block List. + */ + copyCompletionTime?: Date; + /** + * Only appears when x-ms-copy-status is failed or pending. Describes the cause of the last fatal + * or non-fatal copy operation failure. This header does not appear if this blob has never been + * the destination in a Copy Blob operation, or if this blob has been modified after a concluded + * Copy Blob operation using Set Blob Properties, Put Blob, or Put Block List + */ + copyStatusDescription?: string; + /** + * String identifier for this copy operation. Use with Get Blob Properties to check the status of + * this copy operation, or pass to Abort Copy Blob to abort a pending copy. + */ + copyId?: string; + /** + * Contains the number of bytes copied and the total bytes in the source in the last attempted + * Copy Blob operation where this blob was the destination blob. Can show between 0 and + * Content-Length bytes copied. This header does not appear if this blob has never been the + * destination in a Copy Blob operation, or if this blob has been modified after a concluded Copy + * Blob operation using Set Blob Properties, Put Blob, or Put Block List + */ + copyProgress?: string; + /** + * URL up to 2 KB in length that specifies the source blob or file used in the last attempted + * Copy Blob operation where this blob was the destination blob. This header does not appear if + * this blob has never been the destination in a Copy Blob operation, or if this blob has been + * modified after a concluded Copy Blob operation using Set Blob Properties, Put Blob, or Put + * Block List. + */ + copySource?: string; + /** + * State of the copy operation identified by x-ms-copy-id. Possible values include: 'pending', + * 'success', 'aborted', 'failed' + */ + copyStatus?: CopyStatusType; + /** + * Included if the blob is incremental copy blob. + */ + isIncrementalCopy?: boolean; + /** + * Included if the blob is incremental copy blob or incremental copy snapshot, if + * x-ms-copy-status is success. Snapshot time of the last successful incremental copy snapshot + * for this blob. + */ + destinationSnapshot?: string; + /** + * The current sequence number for a page blob. This header is not returned for block blobs or + * append blobs + */ + blobSequenceNumber?: number; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * The number of committed blocks present in the blob. This header is returned only for append + * blobs. + */ + blobCommittedBlockCount?: number; + /** + * The value of this header is set to true if the blob data and application metadata are + * completely encrypted using the specified algorithm. Otherwise, the value is set to false (when + * the blob is unencrypted, or if only parts of the blob/application metadata are encrypted). + */ + isServerEncrypted?: boolean; + /** + * The SHA-256 hash of the encryption key used to encrypt the metadata. This header is only + * returned when the metadata was encrypted with a customer-provided key. + */ + encryptionKeySha256?: string; + /** + * Returns the name of the encryption scope used to encrypt the blob contents and application + * metadata. Note that the absence of this header implies use of the default account encryption + * scope. + */ + encryptionScope?: string; + /** + * The tier of page blob on a premium storage account or tier of block blob on blob storage LRS + * accounts. For a list of allowed premium page blob tiers, see + * https://docs.microsoft.com/en-us/azure/virtual-machines/windows/premium-storage#features. For + * blob storage LRS accounts, valid values are Hot/Cool/Archive. + */ + accessTier?: string; + /** + * For page blobs on a premium storage account only. If the access tier is not explicitly set on + * the blob, the tier is inferred based on its content length and this header will be returned + * with true value. + */ + accessTierInferred?: boolean; + /** + * For blob storage LRS accounts, valid values are + * rehydrate-pending-to-hot/rehydrate-pending-to-cool. If the blob is being rehydrated and is not + * complete then this header is returned indicating that rehydrate is pending and also tells the + * destination tier. + */ + archiveStatus?: string; + /** + * The time the tier was changed on the object. This is only returned if the tier on the block + * blob was ever set. + */ + accessTierChangeTime?: Date; + /** + * A DateTime value returned by the service that uniquely identifies the blob. The value of this + * header indicates the blob version, and may be used in subsequent requests to access this + * version of the blob. + */ + versionId?: string; + /** + * The value of this header indicates whether version of this blob is a current version, see also + * x-ms-version-id header. + */ + isCurrentVersion?: boolean; + /** + * The number of tags associated with the blob + */ + tagCount?: number; + /** + * The time this blob will expire. + */ + expiresOn?: Date; + /** + * If this blob has been sealed + */ + isSealed?: boolean; + /** + * If an object is in rehydrate pending state then this header is returned with priority of + * rehydrate. Valid values are High and Standard. + */ + rehydratePriority?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the blob was + * last read or written to + */ + lastAccessed?: Date; + /** + * UTC date/time value generated by the service that indicates the time at which the blob + * immutability policy will expire. + */ + immutabilityPolicyExpiresOn?: Date; + /** + * Indicates immutability policy mode. Possible values include: 'Mutable', 'Unlocked', 'Locked' + */ + immutabilityPolicyMode?: BlobImmutabilityPolicyMode; + /** + * Indicates if a legal hold is present on the blob. + */ + legalHold?: boolean; + errorCode?: string; +} + +/** + * Defines headers for Delete operation. + */ +export interface PathDeleteHeaders { + /** + * A UTC date/time value generated by the service that indicates the time at which the response + * was initiated. + */ + date?: Date; + /** + * A server-generated UUID recorded in the analytics logs for troubleshooting and correlation. + */ + requestId?: string; + /** + * The version of the REST protocol used to process the request. + */ + version?: string; + /** + * When deleting a directory, the number of paths that are deleted with each invocation is + * limited. If the number of paths to be deleted exceeds this limit, a continuation token is + * returned in this response header. When a continuation token is returned in the response, it + * must be specified in a subsequent invocation of the delete operation to continue deleting the + * directory. + */ + continuation?: string; + /** + * Returned only for hierarchical namespace space enabled accounts when soft delete is enabled. A + * unique identifier for the entity that can be used to restore it. See the Undelete REST API for + * more information. + */ + deletionId?: string; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + errorCode?: string; +} + +/** + * Defines headers for SetAccessControl operation. + */ +export interface PathSetAccessControlHeaders { + /** + * A UTC date/time value generated by the service that indicates the time at which the response + * was initiated. + */ + date?: Date; + /** + * An HTTP entity tag associated with the file or directory. + */ + eTag?: string; + /** + * The data and time the file or directory was last modified. Write operations on the file or + * directory update the last modified time. + */ + lastModified?: Date; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * A server-generated UUID recorded in the analytics logs for troubleshooting and correlation. + */ + requestId?: string; + /** + * The version of the REST protocol used to process the request. + */ + version?: string; +} + +/** + * Defines headers for SetAccessControlRecursive operation. + */ +export interface PathSetAccessControlRecursiveHeaders { + /** + * A UTC date/time value generated by the service that indicates the time at which the response + * was initiated. + */ + date?: Date; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * When performing setAccessControlRecursive on a directory, the number of paths that are + * processed with each invocation is limited. If the number of paths to be processed exceeds + * this limit, a continuation token is returned in this response header. When a continuation + * token is returned in the response, it must be specified in a subsequent invocation of the + * setAccessControlRecursive operation to continue the setAccessControlRecursive operation on the + * directory. + */ + continuation?: string; + /** + * A server-generated UUID recorded in the analytics logs for troubleshooting and correlation. + */ + requestId?: string; + /** + * The version of the REST protocol used to process the request. + */ + version?: string; +} + +/** + * Defines headers for SetProperties operation. + */ +export interface PathSetPropertiesHeaders { + /** + * A UTC date/time value generated by the service that indicates the time at which the response + * was initiated. + */ + date?: Date; + /** + * An HTTP entity tag associated with the file or directory. + */ + eTag?: string; + /** + * The data and time the file or directory was last modified. Write operations on the file or + * directory update the last modified time. + */ + lastModified?: Date; + /** + * If the Cache-Control request header has previously been set for the resource, that value is + * returned in this header. + */ + cacheControl?: string; + /** + * If the Content-Disposition request header has previously been set for the resource, that value + * is returned in this header. + */ + contentDisposition?: string; + /** + * If the Content-Encoding request header has previously been set for the resource, that value is + * returned in this header. + */ + contentEncoding?: string; + /** + * If the Content-Language request header has previously been set for the resource, that value is + * returned in this header. + */ + contentLanguage?: string; + /** + * The size of the resource in bytes. + */ + contentLength?: number; + /** + * The content type specified for the resource. If no content type was specified, the default + * content type is application/octet-stream. + */ + contentType?: string; + /** + * An MD5 hash of the request content. This header is only returned for "Flush" operation. This + * header is returned so that the client can check for message content integrity. This header + * refers to the content of the request, not actual file content. + */ + contentMD5?: Uint8Array; + /** + * User-defined properties associated with the file or directory, in the format of a + * comma-separated list of name and value pairs "n1=v1, n2=v2, ...", where each value is a base64 + * encoded string. Note that the string may only contain ASCII characters in the ISO-8859-1 + * character set. + */ + properties?: string; + /** + * A server-generated UUID recorded in the analytics logs for troubleshooting and correlation. + */ + requestId?: string; + /** + * The version of the REST protocol used to process the request. + */ + version?: string; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; +} + +/** + * Defines headers for FlushData operation. + */ +export interface PathFlushDataHeaders { + /** + * A UTC date/time value generated by the service that indicates the time at which the response + * was initiated. + */ + date?: Date; + /** + * An HTTP entity tag associated with the file or directory. + */ + eTag?: string; + /** + * The data and time the file or directory was last modified. Write operations on the file or + * directory update the last modified time. + */ + lastModified?: Date; + /** + * The size of the resource in bytes. + */ + contentLength?: number; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * A server-generated UUID recorded in the analytics logs for troubleshooting and correlation. + */ + requestId?: string; + /** + * The version of the REST protocol used to process the request. + */ + version?: string; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + isServerEncrypted?: boolean; + /** + * The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned + * when the blob was encrypted with a customer-provided key. + */ + encryptionKeySha256?: string; +} + +/** + * Defines headers for AppendData operation. + */ +export interface PathAppendDataHeaders { + /** + * A UTC date/time value generated by the service that indicates the time at which the response + * was initiated. + */ + date?: Date; + /** + * A server-generated UUID recorded in the analytics logs for troubleshooting and correlation. + */ + requestId?: string; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * The version of the REST protocol used to process the request. + */ + version?: string; + /** + * An HTTP entity tag associated with the file or directory. + */ + eTag?: string; + /** + * If the blob has an MD5 hash and this operation is to read the full blob, this response header + * is returned so that the client can check for message content integrity. + */ + contentMD5?: Uint8Array; + /** + * This header is returned so that the client can check for message content integrity. The value + * of this header is computed by the Blob service; it is not necessarily the same value specified + * in the request headers. + */ + xMsContentCrc64?: Uint8Array; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + isServerEncrypted?: boolean; + /** + * The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned + * when the blob was encrypted with a customer-provided key. + */ + encryptionKeySha256?: string; +} + +/** + * Defines headers for SetExpiry operation. + */ +export interface PathSetExpiryHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated. + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for Undelete operation. + */ +export interface PathUndeleteHeaders { + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * The type of the resource. The value may be "file" or "directory". If not set, the value is + * "file". + */ + resourceType?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated. + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for SetProperties operation. + */ +export interface ServiceSetPropertiesHeaders { + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + errorCode?: string; +} + +/** + * Defines headers for GetProperties operation. + */ +export interface ServiceGetPropertiesHeaders { + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + errorCode?: string; +} + +/** + * Defines headers for GetStatistics operation. + */ +export interface ServiceGetStatisticsHeaders { + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for ListContainersSegment operation. + */ +export interface ServiceListContainersSegmentHeaders { + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + errorCode?: string; +} + +/** + * Defines headers for GetUserDelegationKey operation. + */ +export interface ServiceGetUserDelegationKeyHeaders { + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for GetAccountInfo operation. + */ +export interface ServiceGetAccountInfoHeaders { + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * Identifies the sku name of the account. Possible values include: 'Standard_LRS', + * 'Standard_GRS', 'Standard_RAGRS', 'Standard_ZRS', 'Premium_LRS' + */ + skuName?: SkuName; + /** + * Identifies the account kind. Possible values include: 'Storage', 'BlobStorage', 'StorageV2', + * 'FileStorage', 'BlockBlobStorage' + */ + accountKind?: AccountKind; + /** + * Version 2019-07-07 and newer. Indicates if the account has a hierarchical namespace enabled. + */ + isHierarchicalNamespaceEnabled?: boolean; + errorCode?: string; +} + +/** + * Defines headers for GetAccountInfoWithHead operation. + */ +export interface ServiceGetAccountInfoWithHeadHeaders { + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * Identifies the sku name of the account. Possible values include: 'Standard_LRS', + * 'Standard_GRS', 'Standard_RAGRS', 'Standard_ZRS', 'Premium_LRS' + */ + skuName?: SkuName; + /** + * Identifies the account kind. Possible values include: 'Storage', 'BlobStorage', 'StorageV2', + * 'FileStorage', 'BlockBlobStorage' + */ + accountKind?: AccountKind; + /** + * Version 2019-07-07 and newer. Indicates if the account has a hierarchical namespace enabled. + */ + isHierarchicalNamespaceEnabled?: boolean; + errorCode?: string; +} + +/** + * Defines headers for SubmitBatch operation. + */ +export interface ServiceSubmitBatchHeaders { + /** + * The media type of the body of the response. For batch requests, this is multipart/mixed; + * boundary=batchresponse_GUID + */ + contentType?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + errorCode?: string; +} + +/** + * Defines headers for FilterBlobs operation. + */ +export interface ServiceFilterBlobsHeaders { + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for Create operation. + */ +export interface ContainerCreateHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for GetProperties operation. + */ +export interface ContainerGetPropertiesHeaders { + metadata?: { [propertyName: string]: string }; + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * When a blob is leased, specifies whether the lease is of infinite or fixed duration. Possible + * values include: 'infinite', 'fixed' + */ + leaseDuration?: LeaseDurationType; + /** + * Lease state of the blob. Possible values include: 'available', 'leased', 'expired', + * 'breaking', 'broken' + */ + leaseState?: LeaseStateType; + /** + * The current lease status of the blob. Possible values include: 'locked', 'unlocked' + */ + leaseStatus?: LeaseStatusType; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * Indicated whether data in the container may be accessed publicly and the level of access. + * Possible values include: 'container', 'blob' + */ + blobPublicAccess?: PublicAccessType; + /** + * Indicates whether the container has an immutability policy set on it. + */ + hasImmutabilityPolicy?: boolean; + /** + * Indicates whether the container has a legal hold. + */ + hasLegalHold?: boolean; + /** + * The default encryption scope for the container. + */ + defaultEncryptionScope?: string; + /** + * Indicates whether the container's default encryption scope can be overriden. + */ + denyEncryptionScopeOverride?: boolean; + /** + * Indicates whether version level worm is enabled on a container. + */ + isImmutableStorageWithVersioningEnabled?: boolean; + errorCode?: string; +} + +/** + * Defines headers for GetPropertiesWithHead operation. + */ +export interface ContainerGetPropertiesWithHeadHeaders { + metadata?: { [propertyName: string]: string }; + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * When a blob is leased, specifies whether the lease is of infinite or fixed duration. Possible + * values include: 'infinite', 'fixed' + */ + leaseDuration?: LeaseDurationType; + /** + * Lease state of the blob. Possible values include: 'available', 'leased', 'expired', + * 'breaking', 'broken' + */ + leaseState?: LeaseStateType; + /** + * The current lease status of the blob. Possible values include: 'locked', 'unlocked' + */ + leaseStatus?: LeaseStatusType; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * Indicated whether data in the container may be accessed publicly and the level of access. + * Possible values include: 'container', 'blob' + */ + blobPublicAccess?: PublicAccessType; + /** + * Indicates whether the container has an immutability policy set on it. + */ + hasImmutabilityPolicy?: boolean; + /** + * Indicates whether the container has a legal hold. + */ + hasLegalHold?: boolean; + /** + * The default encryption scope for the container. + */ + defaultEncryptionScope?: string; + /** + * Indicates whether the container's default encryption scope can be overriden. + */ + denyEncryptionScopeOverride?: boolean; + /** + * Indicates whether version level worm is enabled on a container. + */ + isImmutableStorageWithVersioningEnabled?: boolean; + errorCode?: string; +} + +/** + * Defines headers for Delete operation. + */ +export interface ContainerDeleteHeaders { + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for SetMetadata operation. + */ +export interface ContainerSetMetadataHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for GetAccessPolicy operation. + */ +export interface ContainerGetAccessPolicyHeaders { + /** + * Indicated whether data in the container may be accessed publicly and the level of access. + * Possible values include: 'container', 'blob' + */ + blobPublicAccess?: PublicAccessType; + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for SetAccessPolicy operation. + */ +export interface ContainerSetAccessPolicyHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for Restore operation. + */ +export interface ContainerRestoreHeaders { + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for SubmitBatch operation. + */ +export interface ContainerSubmitBatchHeaders { + /** + * The media type of the body of the response. For batch requests, this is multipart/mixed; + * boundary=batchresponse_GUID + */ + contentType?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + errorCode?: string; +} + +/** + * Defines headers for FilterBlobs operation. + */ +export interface ContainerFilterBlobsHeaders { + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for AcquireLease operation. + */ +export interface ContainerAcquireLeaseHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * Uniquely identifies a container's lease + */ + leaseId?: string; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for ReleaseLease operation. + */ +export interface ContainerReleaseLeaseHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for RenewLease operation. + */ +export interface ContainerRenewLeaseHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * Uniquely identifies a container's lease + */ + leaseId?: string; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for BreakLease operation. + */ +export interface ContainerBreakLeaseHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * Approximate time remaining in the lease period, in seconds. + */ + leaseTime?: number; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for ChangeLease operation. + */ +export interface ContainerChangeLeaseHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * Uniquely identifies a container's lease + */ + leaseId?: string; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for GetAccountInfo operation. + */ +export interface ContainerGetAccountInfoHeaders { + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * Identifies the sku name of the account. Possible values include: 'Standard_LRS', + * 'Standard_GRS', 'Standard_RAGRS', 'Standard_ZRS', 'Premium_LRS' + */ + skuName?: SkuName; + /** + * Identifies the account kind. Possible values include: 'Storage', 'BlobStorage', 'StorageV2', + * 'FileStorage', 'BlockBlobStorage' + */ + accountKind?: AccountKind; + errorCode?: string; +} + +/** + * Defines headers for GetAccountInfoWithHead operation. + */ +export interface ContainerGetAccountInfoWithHeadHeaders { + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * Identifies the sku name of the account. Possible values include: 'Standard_LRS', + * 'Standard_GRS', 'Standard_RAGRS', 'Standard_ZRS', 'Premium_LRS' + */ + skuName?: SkuName; + /** + * Identifies the account kind. Possible values include: 'Storage', 'BlobStorage', 'StorageV2', + * 'FileStorage', 'BlockBlobStorage' + */ + accountKind?: AccountKind; + errorCode?: string; +} + +/** + * Defines headers for Create operation. + */ +export interface PageBlobCreateHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * If the blob has an MD5 hash and this operation is to read the full blob, this response header + * is returned so that the client can check for message content integrity. + */ + contentMD5?: Uint8Array; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * A DateTime value returned by the service that uniquely identifies the blob. The value of this + * header indicates the blob version, and may be used in subsequent requests to access this + * version of the blob. + */ + versionId?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + isServerEncrypted?: boolean; + /** + * The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned + * when the blob was encrypted with a customer-provided key. + */ + encryptionKeySha256?: string; + /** + * Returns the name of the encryption scope used to encrypt the blob contents and application + * metadata. Note that the absence of this header implies use of the default account encryption + * scope. + */ + encryptionScope?: string; + errorCode?: string; +} + +/** + * Defines headers for Create operation. + */ +export interface AppendBlobCreateHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * If the blob has an MD5 hash and this operation is to read the full blob, this response header + * is returned so that the client can check for message content integrity. + */ + contentMD5?: Uint8Array; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * A DateTime value returned by the service that uniquely identifies the blob. The value of this + * header indicates the blob version, and may be used in subsequent requests to access this + * version of the blob. + */ + versionId?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + isServerEncrypted?: boolean; + /** + * The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned + * when the blob was encrypted with a customer-provided key. + */ + encryptionKeySha256?: string; + /** + * Returns the name of the encryption scope used to encrypt the blob contents and application + * metadata. Note that the absence of this header implies use of the default account encryption + * scope. + */ + encryptionScope?: string; + errorCode?: string; +} + +/** + * Defines headers for Upload operation. + */ +export interface BlockBlobUploadHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * If the blob has an MD5 hash and this operation is to read the full blob, this response header + * is returned so that the client can check for message content integrity. + */ + contentMD5?: Uint8Array; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * A DateTime value returned by the service that uniquely identifies the blob. The value of this + * header indicates the blob version, and may be used in subsequent requests to access this + * version of the blob. + */ + versionId?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + isServerEncrypted?: boolean; + /** + * The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned + * when the blob was encrypted with a customer-provided key. + */ + encryptionKeySha256?: string; + /** + * Returns the name of the encryption scope used to encrypt the blob contents and application + * metadata. Note that the absence of this header implies use of the default account encryption + * scope. + */ + encryptionScope?: string; + errorCode?: string; +} + +/** + * Defines headers for PutBlobFromUrl operation. + */ +export interface BlockBlobPutBlobFromUrlHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * If the blob has an MD5 hash and this operation is to read the full blob, this response header + * is returned so that the client can check for message content integrity. + */ + contentMD5?: Uint8Array; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * A DateTime value returned by the service that uniquely identifies the blob. The value of this + * header indicates the blob version, and may be used in subsequent requests to access this + * version of the blob. + */ + versionId?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + isServerEncrypted?: boolean; + /** + * The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned + * when the blob was encrypted with a customer-provided key. + */ + encryptionKeySha256?: string; + /** + * Returns the name of the encryption scope used to encrypt the blob contents and application + * metadata. Note that the absence of this header implies use of the default account encryption + * scope. + */ + encryptionScope?: string; + errorCode?: string; +} + +/** + * Defines headers for Undelete operation. + */ +export interface BlobUndeleteHeaders { + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated. + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for SetExpiry operation. + */ +export interface BlobSetExpiryHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated. + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for SetHTTPHeaders operation. + */ +export interface BlobSetHTTPHeadersHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * The current sequence number for a page blob. This header is not returned for block blobs or + * append blobs + */ + blobSequenceNumber?: number; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for SetImmutabilityPolicy operation. + */ +export interface BlobSetImmutabilityPolicyHeaders { + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * Indicates the time the immutability policy will expire. + */ + immutabilityPolicyExpiry?: Date; + /** + * Indicates immutability policy mode. Possible values include: 'Mutable', 'Unlocked', 'Locked' + */ + immutabilityPolicyMode?: BlobImmutabilityPolicyMode; + errorCode?: string; +} + +/** + * Defines headers for DeleteImmutabilityPolicy operation. + */ +export interface BlobDeleteImmutabilityPolicyHeaders { + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for SetLegalHold operation. + */ +export interface BlobSetLegalHoldHeaders { + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * Indicates if the blob has a legal hold. + */ + legalHold?: boolean; + errorCode?: string; +} + +/** + * Defines headers for SetMetadata operation. + */ +export interface BlobSetMetadataHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * A DateTime value returned by the service that uniquely identifies the blob. The value of this + * header indicates the blob version, and may be used in subsequent requests to access this + * version of the blob. + */ + versionId?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + isServerEncrypted?: boolean; + /** + * The SHA-256 hash of the encryption key used to encrypt the metadata. This header is only + * returned when the metadata was encrypted with a customer-provided key. + */ + encryptionKeySha256?: string; + /** + * Returns the name of the encryption scope used to encrypt the blob contents and application + * metadata. Note that the absence of this header implies use of the default account encryption + * scope. + */ + encryptionScope?: string; + errorCode?: string; +} + +/** + * Defines headers for AcquireLease operation. + */ +export interface BlobAcquireLeaseHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the blob was last modified. Any operation that modifies the blob, + * including an update of the blob's metadata or properties, changes the last-modified time of + * the blob. + */ + lastModified?: Date; + /** + * Uniquely identifies a blobs' lease + */ + leaseId?: string; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for ReleaseLease operation. + */ +export interface BlobReleaseLeaseHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the blob was last modified. Any operation that modifies the blob, + * including an update of the blob's metadata or properties, changes the last-modified time of + * the blob. + */ + lastModified?: Date; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for RenewLease operation. + */ +export interface BlobRenewLeaseHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the blob was last modified. Any operation that modifies the blob, + * including an update of the blob's metadata or properties, changes the last-modified time of + * the blob. + */ + lastModified?: Date; + /** + * Uniquely identifies a blobs' lease + */ + leaseId?: string; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for ChangeLease operation. + */ +export interface BlobChangeLeaseHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the blob was last modified. Any operation that modifies the blob, + * including an update of the blob's metadata or properties, changes the last-modified time of + * the blob. + */ + lastModified?: Date; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Uniquely identifies a blobs' lease + */ + leaseId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for BreakLease operation. + */ +export interface BlobBreakLeaseHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the blob was last modified. Any operation that modifies the blob, + * including an update of the blob's metadata or properties, changes the last-modified time of + * the blob. + */ + lastModified?: Date; + /** + * Approximate time remaining in the lease period, in seconds. + */ + leaseTime?: number; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for CreateSnapshot operation. + */ +export interface BlobCreateSnapshotHeaders { + /** + * Uniquely identifies the snapshot and indicates the snapshot version. It may be used in + * subsequent requests to access the snapshot + */ + snapshot?: string; + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * A DateTime value returned by the service that uniquely identifies the blob. The value of this + * header indicates the blob version, and may be used in subsequent requests to access this + * version of the blob. + */ + versionId?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * True if the contents of the request are successfully encrypted using the specified algorithm, + * and false otherwise. For a snapshot request, this header is set to true when metadata was + * provided in the request and encrypted with a customer-provided key. + */ + isServerEncrypted?: boolean; + errorCode?: string; +} + +/** + * Defines headers for StartCopyFromURL operation. + */ +export interface BlobStartCopyFromURLHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * A DateTime value returned by the service that uniquely identifies the blob. The value of this + * header indicates the blob version, and may be used in subsequent requests to access this + * version of the blob. + */ + versionId?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * String identifier for this copy operation. Use with Get Blob Properties to check the status of + * this copy operation, or pass to Abort Copy Blob to abort a pending copy. + */ + copyId?: string; + /** + * State of the copy operation identified by x-ms-copy-id. Possible values include: 'pending', + * 'success', 'aborted', 'failed' + */ + copyStatus?: CopyStatusType; + errorCode?: string; +} + +/** + * Defines headers for CopyFromURL operation. + */ +export interface BlobCopyFromURLHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * A DateTime value returned by the service that uniquely identifies the blob. The value of this + * header indicates the blob version, and may be used in subsequent requests to access this + * version of the blob. + */ + versionId?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * String identifier for this copy operation. + */ + copyId?: string; + /** + * State of the copy operation identified by x-ms-copy-id. Possible values include: 'success' + */ + copyStatus?: SyncCopyStatusType; + /** + * This response header is returned so that the client can check for the integrity of the copied + * content. This header is only returned if the source content MD5 was specified. + */ + contentMD5?: Uint8Array; + /** + * This response header is returned so that the client can check for the integrity of the copied + * content. + */ + xMsContentCrc64?: Uint8Array; + /** + * Returns the name of the encryption scope used to encrypt the blob contents and application + * metadata. Note that the absence of this header implies use of the default account encryption + * scope. + */ + encryptionScope?: string; + errorCode?: string; +} + +/** + * Defines headers for AbortCopyFromURL operation. + */ +export interface BlobAbortCopyFromURLHeaders { + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for SetTier operation. + */ +export interface BlobSetTierHeaders { + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and newer. + */ + version?: string; + errorCode?: string; +} + +/** + * Defines headers for GetAccountInfo operation. + */ +export interface BlobGetAccountInfoHeaders { + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * Identifies the sku name of the account. Possible values include: 'Standard_LRS', + * 'Standard_GRS', 'Standard_RAGRS', 'Standard_ZRS', 'Premium_LRS' + */ + skuName?: SkuName; + /** + * Identifies the account kind. Possible values include: 'Storage', 'BlobStorage', 'StorageV2', + * 'FileStorage', 'BlockBlobStorage' + */ + accountKind?: AccountKind; + errorCode?: string; +} + +/** + * Defines headers for GetAccountInfoWithHead operation. + */ +export interface BlobGetAccountInfoWithHeadHeaders { + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * Identifies the sku name of the account. Possible values include: 'Standard_LRS', + * 'Standard_GRS', 'Standard_RAGRS', 'Standard_ZRS', 'Premium_LRS' + */ + skuName?: SkuName; + /** + * Identifies the account kind. Possible values include: 'Storage', 'BlobStorage', 'StorageV2', + * 'FileStorage', 'BlockBlobStorage' + */ + accountKind?: AccountKind; + errorCode?: string; +} + +/** + * Defines headers for StageBlock operation. + */ +export interface BlockBlobStageBlockHeaders { + /** + * This header is returned so that the client can check for message content integrity. The value + * of this header is computed by the Blob service; it is not necessarily the same value specified + * in the request headers. + */ + contentMD5?: Uint8Array; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * This header is returned so that the client can check for message content integrity. The value + * of this header is computed by the Blob service; it is not necessarily the same value specified + * in the request headers. + */ + xMsContentCrc64?: Uint8Array; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + isServerEncrypted?: boolean; + /** + * The SHA-256 hash of the encryption key used to encrypt the block. This header is only returned + * when the block was encrypted with a customer-provided key. + */ + encryptionKeySha256?: string; + /** + * Returns the name of the encryption scope used to encrypt the blob contents and application + * metadata. Note that the absence of this header implies use of the default account encryption + * scope. + */ + encryptionScope?: string; + errorCode?: string; +} + +/** + * Defines headers for StageBlockFromURL operation. + */ +export interface BlockBlobStageBlockFromURLHeaders { + /** + * This header is returned so that the client can check for message content integrity. The value + * of this header is computed by the Blob service; it is not necessarily the same value specified + * in the request headers. + */ + contentMD5?: Uint8Array; + /** + * This header is returned so that the client can check for message content integrity. The value + * of this header is computed by the Blob service; it is not necessarily the same value specified + * in the request headers. + */ + xMsContentCrc64?: Uint8Array; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + isServerEncrypted?: boolean; + /** + * The SHA-256 hash of the encryption key used to encrypt the block. This header is only returned + * when the block was encrypted with a customer-provided key. + */ + encryptionKeySha256?: string; + /** + * Returns the name of the encryption scope used to encrypt the blob contents and application + * metadata. Note that the absence of this header implies use of the default account encryption + * scope. + */ + encryptionScope?: string; + errorCode?: string; +} + +/** + * Defines headers for CommitBlockList operation. + */ +export interface BlockBlobCommitBlockListHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * This header is returned so that the client can check for message content integrity. This + * header refers to the content of the request, meaning, in this case, the list of blocks, and + * not the content of the blob itself. + */ + contentMD5?: Uint8Array; + /** + * This header is returned so that the client can check for message content integrity. This + * header refers to the content of the request, meaning, in this case, the list of blocks, and + * not the content of the blob itself. + */ + xMsContentCrc64?: Uint8Array; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * A DateTime value returned by the service that uniquely identifies the blob. The value of this + * header indicates the blob version, and may be used in subsequent requests to access this + * version of the blob. + */ + versionId?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + isServerEncrypted?: boolean; + /** + * The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned + * when the blob was encrypted with a customer-provided key. + */ + encryptionKeySha256?: string; + /** + * Returns the name of the encryption scope used to encrypt the blob contents and application + * metadata. Note that the absence of this header implies use of the default account encryption + * scope. + */ + encryptionScope?: string; + errorCode?: string; +} + +/** + * Defines headers for GetBlockList operation. + */ +export interface BlockBlobGetBlockListHeaders { + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * The media type of the body of the response. For Get Block List this is 'application/xml' + */ + contentType?: string; + /** + * The size of the blob in bytes. + */ + blobContentLength?: number; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for UploadPages operation. + */ +export interface PageBlobUploadPagesHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * If the blob has an MD5 hash and this operation is to read the full blob, this response header + * is returned so that the client can check for message content integrity. + */ + contentMD5?: Uint8Array; + /** + * This header is returned so that the client can check for message content integrity. The value + * of this header is computed by the Blob service; it is not necessarily the same value specified + * in the request headers. + */ + xMsContentCrc64?: Uint8Array; + /** + * The current sequence number for the page blob. + */ + blobSequenceNumber?: number; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + isServerEncrypted?: boolean; + /** + * The SHA-256 hash of the encryption key used to encrypt the pages. This header is only returned + * when the pages were encrypted with a customer-provided key. + */ + encryptionKeySha256?: string; + /** + * Returns the name of the encryption scope used to encrypt the blob contents and application + * metadata. Note that the absence of this header implies use of the default account encryption + * scope. + */ + encryptionScope?: string; + errorCode?: string; +} + +/** + * Defines headers for ClearPages operation. + */ +export interface PageBlobClearPagesHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * If the blob has an MD5 hash and this operation is to read the full blob, this response header + * is returned so that the client can check for message content integrity. + */ + contentMD5?: Uint8Array; + /** + * This header is returned so that the client can check for message content integrity. The value + * of this header is computed by the Blob service; it is not necessarily the same value specified + * in the request headers. + */ + xMsContentCrc64?: Uint8Array; + /** + * The current sequence number for the page blob. + */ + blobSequenceNumber?: number; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for UploadPagesFromURL operation. + */ +export interface PageBlobUploadPagesFromURLHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * If the blob has an MD5 hash and this operation is to read the full blob, this response header + * is returned so that the client can check for message content integrity. + */ + contentMD5?: Uint8Array; + /** + * This header is returned so that the client can check for message content integrity. The value + * of this header is computed by the Blob service; it is not necessarily the same value specified + * in the request headers. + */ + xMsContentCrc64?: Uint8Array; + /** + * The current sequence number for the page blob. + */ + blobSequenceNumber?: number; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + isServerEncrypted?: boolean; + /** + * The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned + * when the blob was encrypted with a customer-provided key. + */ + encryptionKeySha256?: string; + /** + * Returns the name of the encryption scope used to encrypt the blob contents and application + * metadata. Note that the absence of this header implies use of the default account encryption + * scope. + */ + encryptionScope?: string; + errorCode?: string; +} + +/** + * Defines headers for GetPageRanges operation. + */ +export interface PageBlobGetPageRangesHeaders { + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * The size of the blob in bytes. + */ + blobContentLength?: number; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for GetPageRangesDiff operation. + */ +export interface PageBlobGetPageRangesDiffHeaders { + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * The size of the blob in bytes. + */ + blobContentLength?: number; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for Resize operation. + */ +export interface PageBlobResizeHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * The current sequence number for a page blob. This header is not returned for block blobs or + * append blobs + */ + blobSequenceNumber?: number; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for UpdateSequenceNumber operation. + */ +export interface PageBlobUpdateSequenceNumberHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * The current sequence number for a page blob. This header is not returned for block blobs or + * append blobs + */ + blobSequenceNumber?: number; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for CopyIncremental operation. + */ +export interface PageBlobCopyIncrementalHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * String identifier for this copy operation. Use with Get Blob Properties to check the status of + * this copy operation, or pass to Abort Copy Blob to abort a pending copy. + */ + copyId?: string; + /** + * State of the copy operation identified by x-ms-copy-id. Possible values include: 'pending', + * 'success', 'aborted', 'failed' + */ + copyStatus?: CopyStatusType; + errorCode?: string; +} + +/** + * Defines headers for AppendBlock operation. + */ +export interface AppendBlobAppendBlockHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * If the blob has an MD5 hash and this operation is to read the full blob, this response header + * is returned so that the client can check for message content integrity. + */ + contentMD5?: Uint8Array; + /** + * This header is returned so that the client can check for message content integrity. The value + * of this header is computed by the Blob service; it is not necessarily the same value specified + * in the request headers. + */ + xMsContentCrc64?: Uint8Array; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * This response header is returned only for append operations. It returns the offset at which + * the block was committed, in bytes. + */ + blobAppendOffset?: string; + /** + * The number of committed blocks present in the blob. This header is returned only for append + * blobs. + */ + blobCommittedBlockCount?: number; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + isServerEncrypted?: boolean; + /** + * The SHA-256 hash of the encryption key used to encrypt the block. This header is only returned + * when the block was encrypted with a customer-provided key. + */ + encryptionKeySha256?: string; + /** + * Returns the name of the encryption scope used to encrypt the blob contents and application + * metadata. Note that the absence of this header implies use of the default account encryption + * scope. + */ + encryptionScope?: string; + errorCode?: string; +} + +/** + * Defines headers for AppendBlockFromUrl operation. + */ +export interface AppendBlobAppendBlockFromUrlHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * If the blob has an MD5 hash and this operation is to read the full blob, this response header + * is returned so that the client can check for message content integrity. + */ + contentMD5?: Uint8Array; + /** + * This header is returned so that the client can check for message content integrity. The value + * of this header is computed by the Blob service; it is not necessarily the same value specified + * in the request headers. + */ + xMsContentCrc64?: Uint8Array; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * This response header is returned only for append operations. It returns the offset at which + * the block was committed, in bytes. + */ + blobAppendOffset?: string; + /** + * The number of committed blocks present in the blob. This header is returned only for append + * blobs. + */ + blobCommittedBlockCount?: number; + /** + * The SHA-256 hash of the encryption key used to encrypt the block. This header is only returned + * when the block was encrypted with a customer-provided key. + */ + encryptionKeySha256?: string; + /** + * Returns the name of the encryption scope used to encrypt the blob contents and application + * metadata. Note that the absence of this header implies use of the default account encryption + * scope. + */ + encryptionScope?: string; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + isServerEncrypted?: boolean; + errorCode?: string; +} + +/** + * Defines headers for Seal operation. + */ +export interface AppendBlobSealHeaders { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * If this blob has been sealed + */ + isSealed?: boolean; + errorCode?: string; +} + +/** + * Defines headers for Query operation. + */ +export interface BlobQueryHeaders { + /** + * Returns the date and time the container was last modified. Any operation that modifies the + * blob, including an update of the blob's metadata or properties, changes the last-modified time + * of the blob. + */ + lastModified?: Date; + metadata?: { [propertyName: string]: string }; + /** + * The number of bytes present in the response body. + */ + contentLength?: number; + /** + * The media type of the body of the response. For Download Blob this is + * 'application/octet-stream' + */ + contentType?: string; + /** + * Indicates the range of bytes returned in the event that the client requested a subset of the + * blob by setting the 'Range' request header. + */ + contentRange?: string; + /** + * The ETag contains a value that you can use to perform operations conditionally. If the request + * version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + eTag?: string; + /** + * If the blob has an MD5 hash and this operation is to read the full blob, this response header + * is returned so that the client can check for message content integrity. + */ + contentMD5?: Uint8Array; + /** + * This header returns the value that was specified for the Content-Encoding request header + */ + contentEncoding?: string; + /** + * This header is returned if it was previously specified for the blob. + */ + cacheControl?: string; + /** + * This header returns the value that was specified for the 'x-ms-blob-content-disposition' + * header. The Content-Disposition response header field conveys additional information about how + * to process the response payload, and also can be used to attach additional metadata. For + * example, if set to attachment, it indicates that the user-agent should not display the + * response, but instead show a Save As dialog with a filename other than the blob name + * specified. + */ + contentDisposition?: string; + /** + * This header returns the value that was specified for the Content-Language request header. + */ + contentLanguage?: string; + /** + * The current sequence number for a page blob. This header is not returned for block blobs or + * append blobs + */ + blobSequenceNumber?: number; + /** + * The blob's type. Possible values include: 'BlockBlob', 'PageBlob', 'AppendBlob' + */ + blobType?: BlobType; + /** + * Conclusion time of the last attempted Copy Blob operation where this blob was the destination + * blob. This value can specify the time of a completed, aborted, or failed copy attempt. This + * header does not appear if a copy is pending, if this blob has never been the destination in a + * Copy Blob operation, or if this blob has been modified after a concluded Copy Blob operation + * using Set Blob Properties, Put Blob, or Put Block List. + */ + copyCompletionTime?: Date; + /** + * Only appears when x-ms-copy-status is failed or pending. Describes the cause of the last fatal + * or non-fatal copy operation failure. This header does not appear if this blob has never been + * the destination in a Copy Blob operation, or if this blob has been modified after a concluded + * Copy Blob operation using Set Blob Properties, Put Blob, or Put Block List + */ + copyStatusDescription?: string; + /** + * String identifier for this copy operation. Use with Get Blob Properties to check the status of + * this copy operation, or pass to Abort Copy Blob to abort a pending copy. + */ + copyId?: string; + /** + * Contains the number of bytes copied and the total bytes in the source in the last attempted + * Copy Blob operation where this blob was the destination blob. Can show between 0 and + * Content-Length bytes copied. This header does not appear if this blob has never been the + * destination in a Copy Blob operation, or if this blob has been modified after a concluded Copy + * Blob operation using Set Blob Properties, Put Blob, or Put Block List + */ + copyProgress?: string; + /** + * URL up to 2 KB in length that specifies the source blob or file used in the last attempted + * Copy Blob operation where this blob was the destination blob. This header does not appear if + * this blob has never been the destination in a Copy Blob operation, or if this blob has been + * modified after a concluded Copy Blob operation using Set Blob Properties, Put Blob, or Put + * Block List. + */ + copySource?: string; + /** + * State of the copy operation identified by x-ms-copy-id. Possible values include: 'pending', + * 'success', 'aborted', 'failed' + */ + copyStatus?: CopyStatusType; + /** + * When a blob is leased, specifies whether the lease is of infinite or fixed duration. Possible + * values include: 'infinite', 'fixed' + */ + leaseDuration?: LeaseDurationType; + /** + * Lease state of the blob. Possible values include: 'available', 'leased', 'expired', + * 'breaking', 'broken' + */ + leaseState?: LeaseStateType; + /** + * The current lease status of the blob. Possible values include: 'locked', 'unlocked' + */ + leaseStatus?: LeaseStatusType; + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * Indicates that the service supports requests for partial blob content. + */ + acceptRanges?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + /** + * The number of committed blocks present in the blob. This header is returned only for append + * blobs. + */ + blobCommittedBlockCount?: number; + /** + * The value of this header is set to true if the blob data and application metadata are + * completely encrypted using the specified algorithm. Otherwise, the value is set to false (when + * the blob is unencrypted, or if only parts of the blob/application metadata are encrypted). + */ + isServerEncrypted?: boolean; + /** + * The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned + * when the blob was encrypted with a customer-provided key. + */ + encryptionKeySha256?: string; + /** + * Returns the name of the encryption scope used to encrypt the blob contents and application + * metadata. Note that the absence of this header implies use of the default account encryption + * scope. + */ + encryptionScope?: string; + /** + * If the blob has a MD5 hash, and if request contains range header (Range or x-ms-range), this + * response header is returned with the value of the whole blob's MD5 value. This value may or + * may not be equal to the value returned in Content-MD5 header, with the latter calculated from + * the requested range + */ + blobContentMD5?: Uint8Array; + /** + * If the request is to read a specified range and the x-ms-range-get-content-crc64 is set to + * true, then the request returns a crc64 for the range, as long as the range size is less than + * or equal to 4 MB. If both x-ms-range-get-content-crc64 and x-ms-range-get-content-md5 is + * specified in the same request, it will fail with 400(Bad Request) + */ + contentCrc64?: Uint8Array; + errorCode?: string; +} + +/** + * Defines headers for GetTags operation. + */ +export interface BlobGetTagsHeaders { + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines headers for SetTags operation. + */ +export interface BlobSetTagsHeaders { + /** + * If a client request id header is sent in the request, this header will be present in the + * response with the same value. + */ + clientRequestId?: string; + /** + * This header uniquely identifies the request that was made and can be used for troubleshooting + * the request. + */ + requestId?: string; + /** + * Indicates the version of the Blob service used to execute the request. This header is returned + * for requests made against version 2009-09-19 and above. + */ + version?: string; + /** + * UTC date/time value generated by the service that indicates the time at which the response was + * initiated + */ + date?: Date; + errorCode?: string; +} + +/** + * Defines values for BlobType. + * Possible values include: 'BlockBlob', 'PageBlob', 'AppendBlob' + * @readonly + * @enum {string} + */ +export enum BlobType { + BlockBlob = 'BlockBlob', + PageBlob = 'PageBlob', + AppendBlob = 'AppendBlob', +} + +/** + * Defines values for LeaseStatusType. + * Possible values include: 'locked', 'unlocked' + * @readonly + * @enum {string} + */ +export enum LeaseStatusType { + Locked = 'locked', + Unlocked = 'unlocked', +} + +/** + * Defines values for LeaseStateType. + * Possible values include: 'available', 'leased', 'expired', 'breaking', 'broken' + * @readonly + * @enum {string} + */ +export enum LeaseStateType { + Available = 'available', + Leased = 'leased', + Expired = 'expired', + Breaking = 'breaking', + Broken = 'broken', +} + +/** + * Defines values for LeaseDurationType. + * Possible values include: 'infinite', 'fixed' + * @readonly + * @enum {string} + */ +export enum LeaseDurationType { + Infinite = 'infinite', + Fixed = 'fixed', +} + +/** + * Defines values for CopyStatusType. + * Possible values include: 'pending', 'success', 'aborted', 'failed' + * @readonly + * @enum {string} + */ +export enum CopyStatusType { + Pending = 'pending', + Success = 'success', + Aborted = 'aborted', + Failed = 'failed', +} + +/** + * Defines values for AccessTier. + * Possible values include: 'P4', 'P6', 'P10', 'P15', 'P20', 'P30', 'P40', 'P50', 'P60', 'P70', + * 'P80', 'Hot', 'Cool', 'Archive', 'Premium' + * @readonly + * @enum {string} + */ +export enum AccessTier { + P4 = 'P4', + P6 = 'P6', + P10 = 'P10', + P15 = 'P15', + P20 = 'P20', + P30 = 'P30', + P40 = 'P40', + P50 = 'P50', + P60 = 'P60', + P70 = 'P70', + P80 = 'P80', + Hot = 'Hot', + Cool = 'Cool', + Archive = 'Archive', + Premium = 'Premium', +} + +/** + * Defines values for ArchiveStatus. + * Possible values include: 'rehydrate-pending-to-hot', 'rehydrate-pending-to-cool' + * @readonly + * @enum {string} + */ +export enum ArchiveStatus { + RehydratePendingToHot = 'rehydrate-pending-to-hot', + RehydratePendingToCool = 'rehydrate-pending-to-cool', +} + +/** + * Defines values for RehydratePriority. + * Possible values include: 'High', 'Standard' + * @readonly + * @enum {string} + */ +export enum RehydratePriority { + High = 'High', + Standard = 'Standard', +} + +/** + * Defines values for BlobImmutabilityPolicyMode. + * Possible values include: 'Mutable', 'Unlocked', 'Locked' + * @readonly + * @enum {string} + */ +export enum BlobImmutabilityPolicyMode { + Mutable = 'Mutable', + Unlocked = 'Unlocked', + Locked = 'Locked', +} + +/** + * Defines values for PublicAccessType. + * Possible values include: 'container', 'blob' + * @readonly + * @enum {string} + */ +export enum PublicAccessType { + Container = 'container', + Blob = 'blob', +} + +/** + * Defines values for StorageErrorCode. + * Possible values include: 'AccountAlreadyExists', 'AccountBeingCreated', 'AccountIsDisabled', + * 'AuthenticationFailed', 'AuthorizationFailure', 'ConditionHeadersNotSupported', + * 'ConditionNotMet', 'EmptyMetadataKey', 'InsufficientAccountPermissions', 'InternalError', + * 'InvalidAuthenticationInfo', 'InvalidHeaderValue', 'InvalidHttpVerb', 'InvalidInput', + * 'InvalidMd5', 'InvalidMetadata', 'InvalidQueryParameterValue', 'InvalidRange', + * 'InvalidResourceName', 'InvalidUri', 'InvalidXmlDocument', 'InvalidXmlNodeValue', 'Md5Mismatch', + * 'MetadataTooLarge', 'MissingContentLengthHeader', 'MissingRequiredQueryParameter', + * 'MissingRequiredHeader', 'MissingRequiredXmlNode', 'MultipleConditionHeadersNotSupported', + * 'OperationTimedOut', 'OutOfRangeInput', 'OutOfRangeQueryParameterValue', 'RequestBodyTooLarge', + * 'ResourceTypeMismatch', 'RequestUrlFailedToParse', 'ResourceAlreadyExists', 'ResourceNotFound', + * 'ServerBusy', 'UnsupportedHeader', 'UnsupportedXmlNode', 'UnsupportedQueryParameter', + * 'UnsupportedHttpVerb', 'AppendPositionConditionNotMet', 'BlobAlreadyExists', + * 'BlobImmutableDueToPolicy', 'BlobNotFound', 'BlobOverwritten', + * 'BlobTierInadequateForContentLength', 'BlobUsesCustomerSpecifiedEncryption', + * 'BlockCountExceedsLimit', 'BlockListTooLong', 'CannotChangeToLowerTier', + * 'CannotVerifyCopySource', 'ContainerAlreadyExists', 'ContainerBeingDeleted', + * 'ContainerDisabled', 'ContainerNotFound', 'ContentLengthLargerThanTierLimit', + * 'CopyAcrossAccountsNotSupported', 'CopyIdMismatch', 'FeatureVersionMismatch', + * 'IncrementalCopyBlobMismatch', 'IncrementalCopyOfEarlierVersionSnapshotNotAllowed', + * 'IncrementalCopySourceMustBeSnapshot', 'InfiniteLeaseDurationRequired', 'InvalidBlobOrBlock', + * 'InvalidBlobTier', 'InvalidBlobType', 'InvalidBlockId', 'InvalidBlockList', 'InvalidOperation', + * 'InvalidPageRange', 'InvalidSourceBlobType', 'InvalidSourceBlobUrl', + * 'InvalidVersionForPageBlobOperation', 'LeaseAlreadyPresent', 'LeaseAlreadyBroken', + * 'LeaseIdMismatchWithBlobOperation', 'LeaseIdMismatchWithContainerOperation', + * 'LeaseIdMismatchWithLeaseOperation', 'LeaseIdMissing', 'LeaseIsBreakingAndCannotBeAcquired', + * 'LeaseIsBreakingAndCannotBeChanged', 'LeaseIsBrokenAndCannotBeRenewed', 'LeaseLost', + * 'LeaseNotPresentWithBlobOperation', 'LeaseNotPresentWithContainerOperation', + * 'LeaseNotPresentWithLeaseOperation', 'MaxBlobSizeConditionNotMet', + * 'NoAuthenticationInformation', 'NoPendingCopyOperation', + * 'OperationNotAllowedOnIncrementalCopyBlob', 'PendingCopyOperation', + * 'PreviousSnapshotCannotBeNewer', 'PreviousSnapshotNotFound', + * 'PreviousSnapshotOperationNotSupported', 'SequenceNumberConditionNotMet', + * 'SequenceNumberIncrementTooLarge', 'SnapshotCountExceeded', 'SnapshotOperationRateExceeded', + * 'SnapshotsPresent', 'SourceConditionNotMet', 'SystemInUse', 'TargetConditionNotMet', + * 'UnauthorizedBlobOverwrite', 'BlobBeingRehydrated', 'BlobArchived', 'BlobNotArchived', + * 'AuthorizationSourceIPMismatch', 'AuthorizationProtocolMismatch', + * 'AuthorizationPermissionMismatch', 'AuthorizationServiceMismatch', + * 'AuthorizationResourceTypeMismatch' + * @readonly + * @enum {string} + */ +export enum StorageErrorCode { + AccountAlreadyExists = 'AccountAlreadyExists', + AccountBeingCreated = 'AccountBeingCreated', + AccountIsDisabled = 'AccountIsDisabled', + AuthenticationFailed = 'AuthenticationFailed', + AuthorizationFailure = 'AuthorizationFailure', + ConditionHeadersNotSupported = 'ConditionHeadersNotSupported', + ConditionNotMet = 'ConditionNotMet', + EmptyMetadataKey = 'EmptyMetadataKey', + InsufficientAccountPermissions = 'InsufficientAccountPermissions', + InternalError = 'InternalError', + InvalidAuthenticationInfo = 'InvalidAuthenticationInfo', + InvalidHeaderValue = 'InvalidHeaderValue', + InvalidHttpVerb = 'InvalidHttpVerb', + InvalidInput = 'InvalidInput', + InvalidMd5 = 'InvalidMd5', + InvalidMetadata = 'InvalidMetadata', + InvalidQueryParameterValue = 'InvalidQueryParameterValue', + InvalidRange = 'InvalidRange', + InvalidResourceName = 'InvalidResourceName', + InvalidUri = 'InvalidUri', + InvalidXmlDocument = 'InvalidXmlDocument', + InvalidXmlNodeValue = 'InvalidXmlNodeValue', + Md5Mismatch = 'Md5Mismatch', + MetadataTooLarge = 'MetadataTooLarge', + MissingContentLengthHeader = 'MissingContentLengthHeader', + MissingRequiredQueryParameter = 'MissingRequiredQueryParameter', + MissingRequiredHeader = 'MissingRequiredHeader', + MissingRequiredXmlNode = 'MissingRequiredXmlNode', + MultipleConditionHeadersNotSupported = 'MultipleConditionHeadersNotSupported', + OperationTimedOut = 'OperationTimedOut', + OutOfRangeInput = 'OutOfRangeInput', + OutOfRangeQueryParameterValue = 'OutOfRangeQueryParameterValue', + RequestBodyTooLarge = 'RequestBodyTooLarge', + ResourceTypeMismatch = 'ResourceTypeMismatch', + RequestUrlFailedToParse = 'RequestUrlFailedToParse', + ResourceAlreadyExists = 'ResourceAlreadyExists', + ResourceNotFound = 'ResourceNotFound', + ServerBusy = 'ServerBusy', + UnsupportedHeader = 'UnsupportedHeader', + UnsupportedXmlNode = 'UnsupportedXmlNode', + UnsupportedQueryParameter = 'UnsupportedQueryParameter', + UnsupportedHttpVerb = 'UnsupportedHttpVerb', + AppendPositionConditionNotMet = 'AppendPositionConditionNotMet', + BlobAlreadyExists = 'BlobAlreadyExists', + BlobImmutableDueToPolicy = 'BlobImmutableDueToPolicy', + BlobNotFound = 'BlobNotFound', + BlobOverwritten = 'BlobOverwritten', + BlobTierInadequateForContentLength = 'BlobTierInadequateForContentLength', + BlobUsesCustomerSpecifiedEncryption = 'BlobUsesCustomerSpecifiedEncryption', + BlockCountExceedsLimit = 'BlockCountExceedsLimit', + BlockListTooLong = 'BlockListTooLong', + CannotChangeToLowerTier = 'CannotChangeToLowerTier', + CannotVerifyCopySource = 'CannotVerifyCopySource', + ContainerAlreadyExists = 'ContainerAlreadyExists', + ContainerBeingDeleted = 'ContainerBeingDeleted', + ContainerDisabled = 'ContainerDisabled', + ContainerNotFound = 'ContainerNotFound', + ContentLengthLargerThanTierLimit = 'ContentLengthLargerThanTierLimit', + CopyAcrossAccountsNotSupported = 'CopyAcrossAccountsNotSupported', + CopyIdMismatch = 'CopyIdMismatch', + FeatureVersionMismatch = 'FeatureVersionMismatch', + IncrementalCopyBlobMismatch = 'IncrementalCopyBlobMismatch', + IncrementalCopyOfEarlierVersionSnapshotNotAllowed = 'IncrementalCopyOfEarlierVersionSnapshotNotAllowed', + IncrementalCopySourceMustBeSnapshot = 'IncrementalCopySourceMustBeSnapshot', + InfiniteLeaseDurationRequired = 'InfiniteLeaseDurationRequired', + InvalidBlobOrBlock = 'InvalidBlobOrBlock', + InvalidBlobTier = 'InvalidBlobTier', + InvalidBlobType = 'InvalidBlobType', + InvalidBlockId = 'InvalidBlockId', + InvalidBlockList = 'InvalidBlockList', + InvalidOperation = 'InvalidOperation', + InvalidPageRange = 'InvalidPageRange', + InvalidSourceBlobType = 'InvalidSourceBlobType', + InvalidSourceBlobUrl = 'InvalidSourceBlobUrl', + InvalidVersionForPageBlobOperation = 'InvalidVersionForPageBlobOperation', + LeaseAlreadyPresent = 'LeaseAlreadyPresent', + LeaseAlreadyBroken = 'LeaseAlreadyBroken', + LeaseIdMismatchWithBlobOperation = 'LeaseIdMismatchWithBlobOperation', + LeaseIdMismatchWithContainerOperation = 'LeaseIdMismatchWithContainerOperation', + LeaseIdMismatchWithLeaseOperation = 'LeaseIdMismatchWithLeaseOperation', + LeaseIdMissing = 'LeaseIdMissing', + LeaseIsBreakingAndCannotBeAcquired = 'LeaseIsBreakingAndCannotBeAcquired', + LeaseIsBreakingAndCannotBeChanged = 'LeaseIsBreakingAndCannotBeChanged', + LeaseIsBrokenAndCannotBeRenewed = 'LeaseIsBrokenAndCannotBeRenewed', + LeaseLost = 'LeaseLost', + LeaseNotPresentWithBlobOperation = 'LeaseNotPresentWithBlobOperation', + LeaseNotPresentWithContainerOperation = 'LeaseNotPresentWithContainerOperation', + LeaseNotPresentWithLeaseOperation = 'LeaseNotPresentWithLeaseOperation', + MaxBlobSizeConditionNotMet = 'MaxBlobSizeConditionNotMet', + NoAuthenticationInformation = 'NoAuthenticationInformation', + NoPendingCopyOperation = 'NoPendingCopyOperation', + OperationNotAllowedOnIncrementalCopyBlob = 'OperationNotAllowedOnIncrementalCopyBlob', + PendingCopyOperation = 'PendingCopyOperation', + PreviousSnapshotCannotBeNewer = 'PreviousSnapshotCannotBeNewer', + PreviousSnapshotNotFound = 'PreviousSnapshotNotFound', + PreviousSnapshotOperationNotSupported = 'PreviousSnapshotOperationNotSupported', + SequenceNumberConditionNotMet = 'SequenceNumberConditionNotMet', + SequenceNumberIncrementTooLarge = 'SequenceNumberIncrementTooLarge', + SnapshotCountExceeded = 'SnapshotCountExceeded', + SnapshotOperationRateExceeded = 'SnapshotOperationRateExceeded', + SnapshotsPresent = 'SnapshotsPresent', + SourceConditionNotMet = 'SourceConditionNotMet', + SystemInUse = 'SystemInUse', + TargetConditionNotMet = 'TargetConditionNotMet', + UnauthorizedBlobOverwrite = 'UnauthorizedBlobOverwrite', + BlobBeingRehydrated = 'BlobBeingRehydrated', + BlobArchived = 'BlobArchived', + BlobNotArchived = 'BlobNotArchived', + AuthorizationSourceIPMismatch = 'AuthorizationSourceIPMismatch', + AuthorizationProtocolMismatch = 'AuthorizationProtocolMismatch', + AuthorizationPermissionMismatch = 'AuthorizationPermissionMismatch', + AuthorizationServiceMismatch = 'AuthorizationServiceMismatch', + AuthorizationResourceTypeMismatch = 'AuthorizationResourceTypeMismatch', +} + +/** + * Defines values for GeoReplicationStatusType. + * Possible values include: 'live', 'bootstrap', 'unavailable' + * @readonly + * @enum {string} + */ +export enum GeoReplicationStatusType { + Live = 'live', + Bootstrap = 'bootstrap', + Unavailable = 'unavailable', +} + +/** + * Defines values for QueryFormatType. + * Possible values include: 'delimited', 'json', 'arrow', 'parquet' + * @readonly + * @enum {string} + */ +export enum QueryFormatType { + Delimited = 'delimited', + Json = 'json', + Arrow = 'arrow', + Parquet = 'parquet', +} + +/** + * Defines values for DeleteSnapshotsOptionType. + * Possible values include: 'include', 'only' + * @readonly + * @enum {string} + */ +export enum DeleteSnapshotsOptionType { + Include = 'include', + Only = 'only', +} + +/** + * Defines values for BlobDeleteType. + * Possible values include: 'Permanent' + * @readonly + * @enum {string} + */ +export enum BlobDeleteType { + Permanent = 'Permanent', +} + +/** + * Defines values for PathSetAccessControlRecursiveMode. + * Possible values include: 'set', 'modify', 'remove' + * @readonly + * @enum {string} + */ +export enum PathSetAccessControlRecursiveMode { + Set = 'set', + Modify = 'modify', + Remove = 'remove', +} + +/** + * Defines values for LeaseAction. + * Possible values include: 'acquire', 'release', 'renew', 'break', 'change', 'auto-renew', + * 'acquire-release' + * @readonly + * @enum {string} + */ +export enum LeaseAction { + Acquire = 'acquire', + Release = 'release', + Renew = 'renew', + Break = 'break', + Change = 'change', + AutoRenew = 'auto-renew', + AcquireRelease = 'acquire-release', +} + +/** + * Defines values for PathExpiryOptions. + * Possible values include: 'NeverExpire', 'RelativeToCreation', 'RelativeToNow', 'Absolute' + * @readonly + * @enum {string} + */ +export enum PathExpiryOptions { + NeverExpire = 'NeverExpire', + RelativeToCreation = 'RelativeToCreation', + RelativeToNow = 'RelativeToNow', + Absolute = 'Absolute', +} + +/** + * Defines values for ListBlobsIncludeItem. + * Possible values include: '', 'copy', 'deleted', 'metadata', 'snapshots', 'uncommittedblobs', + * 'versions', 'tags', 'immutabilitypolicy', 'legalhold', 'deletedwithversions', 'permissions' + * @readonly + * @enum {string} + */ +export enum ListBlobsIncludeItem { + EmptyString = '', + Copy = 'copy', + Deleted = 'deleted', + Metadata = 'metadata', + Snapshots = 'snapshots', + Uncommittedblobs = 'uncommittedblobs', + Versions = 'versions', + Tags = 'tags', + Immutabilitypolicy = 'immutabilitypolicy', + Legalhold = 'legalhold', + Deletedwithversions = 'deletedwithversions', + Permissions = 'permissions', +} + +/** + * Defines values for ListBlobsShowOnly. + * Possible values include: 'deleted' + * @readonly + * @enum {string} + */ +export enum ListBlobsShowOnly { + Deleted = 'deleted', +} + +/** + * Defines values for EncryptionAlgorithmType. + * Possible values include: 'AES256' + * @readonly + * @enum {string} + */ +export enum EncryptionAlgorithmType { + AES256 = 'AES256', +} + +/** + * Defines values for PremiumPageBlobAccessTier. + * Possible values include: 'P4', 'P6', 'P10', 'P15', 'P20', 'P30', 'P40', 'P50', 'P60', 'P70', + * 'P80' + * @readonly + * @enum {string} + */ +export enum PremiumPageBlobAccessTier { + P4 = 'P4', + P6 = 'P6', + P10 = 'P10', + P15 = 'P15', + P20 = 'P20', + P30 = 'P30', + P40 = 'P40', + P50 = 'P50', + P60 = 'P60', + P70 = 'P70', + P80 = 'P80', +} + +/** + * Defines values for BlobExpiryOptions. + * Possible values include: 'NeverExpire', 'RelativeToCreation', 'RelativeToNow', 'Absolute' + * @readonly + * @enum {string} + */ +export enum BlobExpiryOptions { + NeverExpire = 'NeverExpire', + RelativeToCreation = 'RelativeToCreation', + RelativeToNow = 'RelativeToNow', + Absolute = 'Absolute', +} + +/** + * Defines values for BlockListType. + * Possible values include: 'committed', 'uncommitted', 'all' + * @readonly + * @enum {string} + */ +export enum BlockListType { + Committed = 'committed', + Uncommitted = 'uncommitted', + All = 'all', +} + +/** + * Defines values for BlobCopySourceTags. + * Possible values include: 'REPLACE', 'COPY' + * @readonly + * @enum {string} + */ +export enum BlobCopySourceTags { + REPLACE = 'REPLACE', + COPY = 'COPY', +} + +/** + * Defines values for FilterBlobsIncludeItem. + * Possible values include: 'none', 'versions' + * @readonly + * @enum {string} + */ +export enum FilterBlobsIncludeItem { + None = 'none', + Versions = 'versions', +} + +/** + * Defines values for ListContainersIncludeType. + * Possible values include: '', 'metadata', 'deleted', 'system' + * @readonly + * @enum {string} + */ +export enum ListContainersIncludeType { + EmptyString = '', + Metadata = 'metadata', + Deleted = 'deleted', + System = 'system', +} + +/** + * Defines values for SequenceNumberActionType. + * Possible values include: 'max', 'update', 'increment' + * @readonly + * @enum {string} + */ +export enum SequenceNumberActionType { + Max = 'max', + Update = 'update', + Increment = 'increment', +} + +/** + * Defines values for PathResourceType. + * Possible values include: 'directory', 'file' + * @readonly + * @enum {string} + */ +export enum PathResourceType { + Directory = 'directory', + File = 'file', +} + +/** + * Defines values for PathRenameMode. + * Possible values include: 'legacy', 'posix' + * @readonly + * @enum {string} + */ +export enum PathRenameMode { + Legacy = 'legacy', + Posix = 'posix', +} + +/** + * Defines values for PathUpdateAction. + * Possible values include: 'append', 'flush', 'setProperties', 'setAccessControl', + * 'setAccessControlRecursive' + * @readonly + * @enum {string} + */ +export enum PathUpdateAction { + Append = 'append', + Flush = 'flush', + SetProperties = 'setProperties', + SetAccessControl = 'setAccessControl', + SetAccessControlRecursive = 'setAccessControlRecursive', +} + +/** + * Defines values for PathLeaseAction. + * Possible values include: 'acquire', 'break', 'change', 'renew', 'release' + * @readonly + * @enum {string} + */ +export enum PathLeaseAction { + Acquire = 'acquire', + Break = 'break', + Change = 'change', + Renew = 'renew', + Release = 'release', +} + +/** + * Defines values for PathGetPropertiesAction. + * Possible values include: 'getAccessControl', 'getStatus' + * @readonly + * @enum {string} + */ +export enum PathGetPropertiesAction { + GetAccessControl = 'getAccessControl', + GetStatus = 'getStatus', +} + +/** + * Defines values for SkuName. + * Possible values include: 'Standard_LRS', 'Standard_GRS', 'Standard_RAGRS', 'Standard_ZRS', + * 'Premium_LRS' + * @readonly + * @enum {string} + */ +export enum SkuName { + StandardLRS = 'Standard_LRS', + StandardGRS = 'Standard_GRS', + StandardRAGRS = 'Standard_RAGRS', + StandardZRS = 'Standard_ZRS', + PremiumLRS = 'Premium_LRS', +} + +/** + * Defines values for AccountKind. + * Possible values include: 'Storage', 'BlobStorage', 'StorageV2', 'FileStorage', + * 'BlockBlobStorage' + * @readonly + * @enum {string} + */ +export enum AccountKind { + Storage = 'Storage', + BlobStorage = 'BlobStorage', + StorageV2 = 'StorageV2', + FileStorage = 'FileStorage', + BlockBlobStorage = 'BlockBlobStorage', +} + +/** + * Defines values for SyncCopyStatusType. + * Possible values include: 'success' + * @readonly + * @enum {string} + */ +export enum SyncCopyStatusType { + Success = 'success', +} + +/** + * Contains response data for the listFileSystems operation. + */ +export type ServiceListFileSystemsResponse = FileSystemList & ServiceListFileSystemsHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the setProperties operation. + */ +export type ServiceSetPropertiesResponse = ServiceSetPropertiesHeaders & { + /** + * The response status code. + */ + statusCode: 202; +}; + +/** + * Contains response data for the getProperties operation. + */ +export type ServiceGetPropertiesResponse = StorageServiceProperties & ServiceGetPropertiesHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the getStatistics operation. + */ +export type ServiceGetStatisticsResponse = StorageServiceStats & ServiceGetStatisticsHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the listContainersSegment operation. + */ +export type ServiceListContainersSegmentResponse = ListContainersSegmentResponse & ServiceListContainersSegmentHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the getUserDelegationKey operation. + */ +export type ServiceGetUserDelegationKeyResponse = UserDelegationKey & ServiceGetUserDelegationKeyHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the getAccountInfo operation. + */ +export type ServiceGetAccountInfoResponse = ServiceGetAccountInfoHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the getAccountInfoWithHead operation. + */ +export type ServiceGetAccountInfoWithHeadResponse = ServiceGetAccountInfoWithHeadHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the submitBatch operation. + */ +export type ServiceSubmitBatchResponse = ServiceSubmitBatchHeaders & { + /** + * The response body as a node.js Readable stream. + */ + body?: NodeJS.ReadableStream; +} & { + /** + * The response status code. + */ + statusCode: 202; +}; + +/** + * Contains response data for the filterBlobs operation. + */ +export type ServiceFilterBlobsResponse = FilterBlobSegment & ServiceFilterBlobsHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the create operation. + */ +export type FileSystemCreateResponse = FileSystemCreateHeaders & { + /** + * The response status code. + */ + statusCode: 201; +}; + +/** + * Contains response data for the setProperties operation. + */ +export type FileSystemSetPropertiesResponse = FileSystemSetPropertiesHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the getProperties operation. + */ +export type FileSystemGetPropertiesResponse = FileSystemGetPropertiesHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the deleteMethod operation. + */ +export type FileSystemDeleteResponse = FileSystemDeleteHeaders & { + /** + * The response status code. + */ + statusCode: 202; +}; + +/** + * Contains response data for the listPaths operation. + */ +export type FileSystemListPathsResponse = PathList & FileSystemListPathsHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the listBlobFlatSegment operation. + */ +export type FileSystemListBlobFlatSegmentResponse = ListBlobsFlatSegmentResponse & FileSystemListBlobFlatSegmentHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the listBlobHierarchySegment operation. + */ +export type FileSystemListBlobHierarchySegmentResponse = ListBlobsHierarchySegmentResponse & FileSystemListBlobHierarchySegmentHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the create operation. + */ +export type PathCreateResponse = PathCreateHeaders & { + /** + * The response status code. + */ + statusCode: 201; +}; + +/** + * Contains response data for the update operation. + */ +export type PathUpdateResponse = SetAccessControlRecursiveResponse & PathUpdateHeaders & { + /** + * The response status code. + */ + statusCode: 200 | 202; +}; + +/** + * Contains response data for the lease operation. + */ +export type PathLeaseResponse = PathLeaseHeaders & { + /** + * The response status code. + */ + statusCode: 200 | 201 | 202; +}; + +/** + * Contains response data for the read operation. + */ +export type PathReadResponse = PathReadHeaders & { + /** + * The response body as a node.js Readable stream. + */ + body?: NodeJS.ReadableStream; +} & { + /** + * The response status code. + */ + statusCode: 200 | 206; +}; + +/** + * Contains response data for the getProperties operation. + */ +export type PathGetPropertiesResponse = PathGetPropertiesHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the deleteMethod operation. + */ +export type PathDeleteResponse = PathDeleteHeaders & { + /** + * The response status code. + */ + statusCode: 200 | 202; +}; + +/** + * Contains response data for the setAccessControl operation. + */ +export type PathSetAccessControlResponse = PathSetAccessControlHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the setAccessControlRecursive operation. + */ +export type PathSetAccessControlRecursiveResponse = SetAccessControlRecursiveResponse & PathSetAccessControlRecursiveHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the setProperties operation. + */ +export type PathSetPropertiesResponse = PathSetPropertiesHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the flushData operation. + */ +export type PathFlushDataResponse = PathFlushDataHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the appendData operation. + */ +export type PathAppendDataResponse = PathAppendDataHeaders & { + /** + * The response status code. + */ + statusCode: 202; +}; + +/** + * Contains response data for the setExpiry operation. + */ +export type PathSetExpiryResponse = PathSetExpiryHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the undelete operation. + */ +export type PathUndeleteResponse = PathUndeleteHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the create operation. + */ +export type ContainerCreateResponse = ContainerCreateHeaders & { + /** + * The response status code. + */ + statusCode: 201; +}; + +/** + * Contains response data for the getProperties operation. + */ +export type ContainerGetPropertiesResponse = ContainerGetPropertiesHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the getPropertiesWithHead operation. + */ +export type ContainerGetPropertiesWithHeadResponse = ContainerGetPropertiesWithHeadHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the deleteMethod operation. + */ +export type ContainerDeleteResponse = ContainerDeleteHeaders & { + /** + * The response status code. + */ + statusCode: 202; +}; + +/** + * Contains response data for the setMetadata operation. + */ +export type ContainerSetMetadataResponse = ContainerSetMetadataHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the getAccessPolicy operation. + */ +export type ContainerGetAccessPolicyResponse = Array & ContainerGetAccessPolicyHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the setAccessPolicy operation. + */ +export type ContainerSetAccessPolicyResponse = ContainerSetAccessPolicyHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the restore operation. + */ +export type ContainerRestoreResponse = ContainerRestoreHeaders & { + /** + * The response status code. + */ + statusCode: 201; +}; + +/** + * Contains response data for the submitBatch operation. + */ +export type ContainerSubmitBatchResponse = ContainerSubmitBatchHeaders & { + /** + * The response body as a node.js Readable stream. + */ + body?: NodeJS.ReadableStream; +} & { + /** + * The response status code. + */ + statusCode: 202; +}; + +/** + * Contains response data for the filterBlobs operation. + */ +export type ContainerFilterBlobsResponse = FilterBlobSegment & ContainerFilterBlobsHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the acquireLease operation. + */ +export type ContainerAcquireLeaseResponse = ContainerAcquireLeaseHeaders & { + /** + * The response status code. + */ + statusCode: 201; +}; + +/** + * Contains response data for the releaseLease operation. + */ +export type ContainerReleaseLeaseResponse = ContainerReleaseLeaseHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the renewLease operation. + */ +export type ContainerRenewLeaseResponse = ContainerRenewLeaseHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the breakLease operation. + */ +export type ContainerBreakLeaseResponse = ContainerBreakLeaseHeaders & { + /** + * The response status code. + */ + statusCode: 202; +}; + +/** + * Contains response data for the changeLease operation. + */ +export type ContainerChangeLeaseResponse = ContainerChangeLeaseHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the getAccountInfo operation. + */ +export type ContainerGetAccountInfoResponse = ContainerGetAccountInfoHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the getAccountInfoWithHead operation. + */ +export type ContainerGetAccountInfoWithHeadResponse = ContainerGetAccountInfoWithHeadHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the create operation. + */ +export type PageBlobCreateResponse = PageBlobCreateHeaders & { + /** + * The response status code. + */ + statusCode: 201; +}; + +/** + * Contains response data for the uploadPages operation. + */ +export type PageBlobUploadPagesResponse = PageBlobUploadPagesHeaders & { + /** + * The response status code. + */ + statusCode: 201; +}; + +/** + * Contains response data for the clearPages operation. + */ +export type PageBlobClearPagesResponse = PageBlobClearPagesHeaders & { + /** + * The response status code. + */ + statusCode: 201; +}; + +/** + * Contains response data for the uploadPagesFromURL operation. + */ +export type PageBlobUploadPagesFromURLResponse = PageBlobUploadPagesFromURLHeaders & { + /** + * The response status code. + */ + statusCode: 201; +}; + +/** + * Contains response data for the getPageRanges operation. + */ +export type PageBlobGetPageRangesResponse = PageList & PageBlobGetPageRangesHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the getPageRangesDiff operation. + */ +export type PageBlobGetPageRangesDiffResponse = PageList & PageBlobGetPageRangesDiffHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the resize operation. + */ +export type PageBlobResizeResponse = PageBlobResizeHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the updateSequenceNumber operation. + */ +export type PageBlobUpdateSequenceNumberResponse = PageBlobUpdateSequenceNumberHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the copyIncremental operation. + */ +export type PageBlobCopyIncrementalResponse = PageBlobCopyIncrementalHeaders & { + /** + * The response status code. + */ + statusCode: 202; +}; + +/** + * Contains response data for the create operation. + */ +export type AppendBlobCreateResponse = AppendBlobCreateHeaders & { + /** + * The response status code. + */ + statusCode: 201; +}; + +/** + * Contains response data for the appendBlock operation. + */ +export type AppendBlobAppendBlockResponse = AppendBlobAppendBlockHeaders & { + /** + * The response status code. + */ + statusCode: 201; +}; + +/** + * Contains response data for the appendBlockFromUrl operation. + */ +export type AppendBlobAppendBlockFromUrlResponse = AppendBlobAppendBlockFromUrlHeaders & { + /** + * The response status code. + */ + statusCode: 201; +}; + +/** + * Contains response data for the seal operation. + */ +export type AppendBlobSealResponse = AppendBlobSealHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the upload operation. + */ +export type BlockBlobUploadResponse = BlockBlobUploadHeaders & { + /** + * The response status code. + */ + statusCode: 201; +}; + +/** + * Contains response data for the putBlobFromUrl operation. + */ +export type BlockBlobPutBlobFromUrlResponse = BlockBlobPutBlobFromUrlHeaders & { + /** + * The response status code. + */ + statusCode: 201; +}; + +/** + * Contains response data for the stageBlock operation. + */ +export type BlockBlobStageBlockResponse = BlockBlobStageBlockHeaders & { + /** + * The response status code. + */ + statusCode: 201; +}; + +/** + * Contains response data for the stageBlockFromURL operation. + */ +export type BlockBlobStageBlockFromURLResponse = BlockBlobStageBlockFromURLHeaders & { + /** + * The response status code. + */ + statusCode: 201; +}; + +/** + * Contains response data for the commitBlockList operation. + */ +export type BlockBlobCommitBlockListResponse = BlockBlobCommitBlockListHeaders & { + /** + * The response status code. + */ + statusCode: 201; +}; + +/** + * Contains response data for the getBlockList operation. + */ +export type BlockBlobGetBlockListResponse = BlockList & BlockBlobGetBlockListHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the undelete operation. + */ +export type BlobUndeleteResponse = BlobUndeleteHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the setExpiry operation. + */ +export type BlobSetExpiryResponse = BlobSetExpiryHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the setHTTPHeaders operation. + */ +export type BlobSetHTTPHeadersResponse = BlobSetHTTPHeadersHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the setImmutabilityPolicy operation. + */ +export type BlobSetImmutabilityPolicyResponse = BlobSetImmutabilityPolicyHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the deleteImmutabilityPolicy operation. + */ +export type BlobDeleteImmutabilityPolicyResponse = BlobDeleteImmutabilityPolicyHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the setLegalHold operation. + */ +export type BlobSetLegalHoldResponse = BlobSetLegalHoldHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the setMetadata operation. + */ +export type BlobSetMetadataResponse = BlobSetMetadataHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the acquireLease operation. + */ +export type BlobAcquireLeaseResponse = BlobAcquireLeaseHeaders & { + /** + * The response status code. + */ + statusCode: 201; +}; + +/** + * Contains response data for the releaseLease operation. + */ +export type BlobReleaseLeaseResponse = BlobReleaseLeaseHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the renewLease operation. + */ +export type BlobRenewLeaseResponse = BlobRenewLeaseHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the changeLease operation. + */ +export type BlobChangeLeaseResponse = BlobChangeLeaseHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the breakLease operation. + */ +export type BlobBreakLeaseResponse = BlobBreakLeaseHeaders & { + /** + * The response status code. + */ + statusCode: 202; +}; + +/** + * Contains response data for the createSnapshot operation. + */ +export type BlobCreateSnapshotResponse = BlobCreateSnapshotHeaders & { + /** + * The response status code. + */ + statusCode: 201; +}; + +/** + * Contains response data for the startCopyFromURL operation. + */ +export type BlobStartCopyFromURLResponse = BlobStartCopyFromURLHeaders & { + /** + * The response status code. + */ + statusCode: 202; +}; + +/** + * Contains response data for the copyFromURL operation. + */ +export type BlobCopyFromURLResponse = BlobCopyFromURLHeaders & { + /** + * The response status code. + */ + statusCode: 202; +}; + +/** + * Contains response data for the abortCopyFromURL operation. + */ +export type BlobAbortCopyFromURLResponse = BlobAbortCopyFromURLHeaders & { + /** + * The response status code. + */ + statusCode: 204; +}; + +/** + * Contains response data for the setTier operation. + */ +export type BlobSetTierResponse = BlobSetTierHeaders & { + /** + * The response status code. + */ + statusCode: 200 | 202; +}; + +/** + * Contains response data for the getAccountInfo operation. + */ +export type BlobGetAccountInfoResponse = BlobGetAccountInfoHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the getAccountInfoWithHead operation. + */ +export type BlobGetAccountInfoWithHeadResponse = BlobGetAccountInfoWithHeadHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the query operation. + */ +export type BlobQueryResponse = BlobQueryHeaders & { + /** + * The response body as a node.js Readable stream. + */ + body?: NodeJS.ReadableStream; +} & { + /** + * The response status code. + */ + statusCode: 200 | 206; +}; + +/** + * Contains response data for the getTags operation. + */ +export type BlobGetTagsResponse = BlobTags & BlobGetTagsHeaders & { + /** + * The response status code. + */ + statusCode: 200; +}; + +/** + * Contains response data for the setTags operation. + */ +export type BlobSetTagsResponse = BlobSetTagsHeaders & { + /** + * The response status code. + */ + statusCode: 204; +}; diff --git a/src/dfs/generated/artifacts/operation.ts b/src/dfs/generated/artifacts/operation.ts new file mode 100644 index 000000000..1c81c7a33 --- /dev/null +++ b/src/dfs/generated/artifacts/operation.ts @@ -0,0 +1,99 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +export enum Operation { + Service_ListFileSystems, + Service_SetProperties, + Service_GetProperties, + Service_GetStatistics, + Service_ListContainersSegment, + Service_GetUserDelegationKey, + Service_GetAccountInfo, + Service_GetAccountInfoWithHead, + Service_SubmitBatch, + Service_FilterBlobs, + FileSystem_Create, + FileSystem_SetProperties, + FileSystem_GetProperties, + FileSystem_Delete, + FileSystem_ListPaths, + FileSystem_ListBlobFlatSegment, + FileSystem_ListBlobHierarchySegment, + Path_Create, + Path_Update, + Path_Lease, + Path_Read, + Path_GetProperties, + Path_Delete, + Path_SetAccessControl, + Path_SetAccessControlRecursive, + Path_SetProperties, + Path_FlushData, + Path_AppendData, + Path_SetExpiry, + Path_Undelete, + Container_Create, + Container_GetProperties, + Container_GetPropertiesWithHead, + Container_Delete, + Container_SetMetadata, + Container_GetAccessPolicy, + Container_SetAccessPolicy, + Container_Restore, + Container_SubmitBatch, + Container_FilterBlobs, + Container_AcquireLease, + Container_ReleaseLease, + Container_RenewLease, + Container_BreakLease, + Container_ChangeLease, + Container_GetAccountInfo, + Container_GetAccountInfoWithHead, + PageBlob_Create, + PageBlob_UploadPages, + PageBlob_ClearPages, + PageBlob_UploadPagesFromURL, + PageBlob_GetPageRanges, + PageBlob_GetPageRangesDiff, + PageBlob_Resize, + PageBlob_UpdateSequenceNumber, + PageBlob_CopyIncremental, + AppendBlob_Create, + AppendBlob_AppendBlock, + AppendBlob_AppendBlockFromUrl, + AppendBlob_Seal, + BlockBlob_Upload, + BlockBlob_PutBlobFromUrl, + BlockBlob_StageBlock, + BlockBlob_StageBlockFromURL, + BlockBlob_CommitBlockList, + BlockBlob_GetBlockList, + Blob_Undelete, + Blob_SetExpiry, + Blob_SetHTTPHeaders, + Blob_SetImmutabilityPolicy, + Blob_DeleteImmutabilityPolicy, + Blob_SetLegalHold, + Blob_SetMetadata, + Blob_AcquireLease, + Blob_ReleaseLease, + Blob_RenewLease, + Blob_ChangeLease, + Blob_BreakLease, + Blob_CreateSnapshot, + Blob_StartCopyFromURL, + Blob_CopyFromURL, + Blob_AbortCopyFromURL, + Blob_SetTier, + Blob_GetAccountInfo, + Blob_GetAccountInfoWithHead, + Blob_Query, + Blob_GetTags, + Blob_SetTags, +} +export default Operation; diff --git a/src/dfs/generated/artifacts/parameters.ts b/src/dfs/generated/artifacts/parameters.ts new file mode 100644 index 000000000..e4ab9ed32 --- /dev/null +++ b/src/dfs/generated/artifacts/parameters.ts @@ -0,0 +1,2305 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +// tslint:disable:quotemark +// tslint:disable:object-literal-sort-keys + +import * as msRest from "@azure/ms-rest-js"; + +export const access: msRest.OperationParameter = { + parameterPath: [ + "options", + "access" + ], + mapper: { + serializedName: "x-ms-blob-public-access", + type: { + name: "String" + } + } +}; +export const acl: msRest.OperationParameter = { + parameterPath: [ + "options", + "acl" + ], + mapper: { + serializedName: "x-ms-acl", + type: { + name: "String" + } + } +}; +export const action0: msRest.OperationQueryParameter = { + parameterPath: "action", + mapper: { + required: true, + serializedName: "action", + type: { + name: "Enum", + allowedValues: [ + "append", + "flush", + "setProperties", + "setAccessControl", + "setAccessControlRecursive" + ] + } + } +}; +export const action1: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "action" + ], + mapper: { + serializedName: "action", + type: { + name: "Enum", + allowedValues: [ + "getAccessControl", + "getStatus" + ] + } + } +}; +export const action10: msRest.OperationParameter = { + parameterPath: "action", + mapper: { + required: true, + isConstant: true, + serializedName: "x-ms-lease-action", + defaultValue: 'break', + type: { + name: "String" + } + } +}; +export const action11: msRest.OperationParameter = { + parameterPath: "action", + mapper: { + required: true, + isConstant: true, + serializedName: "x-ms-lease-action", + defaultValue: 'change', + type: { + name: "String" + } + } +}; +export const action2: msRest.OperationQueryParameter = { + parameterPath: "action", + mapper: { + required: true, + isConstant: true, + serializedName: "action", + defaultValue: 'setAccessControl', + type: { + name: "String" + } + } +}; +export const action3: msRest.OperationQueryParameter = { + parameterPath: "action", + mapper: { + required: true, + isConstant: true, + serializedName: "action", + defaultValue: 'setAccessControlRecursive', + type: { + name: "String" + } + } +}; +export const action4: msRest.OperationQueryParameter = { + parameterPath: "action", + mapper: { + required: true, + isConstant: true, + serializedName: "action", + defaultValue: 'setProperties', + type: { + name: "String" + } + } +}; +export const action5: msRest.OperationQueryParameter = { + parameterPath: "action", + mapper: { + required: true, + isConstant: true, + serializedName: "action", + defaultValue: 'flush', + type: { + name: "String" + } + } +}; +export const action6: msRest.OperationQueryParameter = { + parameterPath: "action", + mapper: { + required: true, + isConstant: true, + serializedName: "action", + defaultValue: 'append', + type: { + name: "String" + } + } +}; +export const action7: msRest.OperationParameter = { + parameterPath: "action", + mapper: { + required: true, + isConstant: true, + serializedName: "x-ms-lease-action", + defaultValue: 'acquire', + type: { + name: "String" + } + } +}; +export const action8: msRest.OperationParameter = { + parameterPath: "action", + mapper: { + required: true, + isConstant: true, + serializedName: "x-ms-lease-action", + defaultValue: 'release', + type: { + name: "String" + } + } +}; +export const action9: msRest.OperationParameter = { + parameterPath: "action", + mapper: { + required: true, + isConstant: true, + serializedName: "x-ms-lease-action", + defaultValue: 'renew', + type: { + name: "String" + } + } +}; +export const appendPosition: msRest.OperationParameter = { + parameterPath: [ + "options", + "appendPositionAccessConditions", + "appendPosition" + ], + mapper: { + serializedName: "x-ms-blob-condition-appendpos", + type: { + name: "Number" + } + } +}; +export const blobCacheControl: msRest.OperationParameter = { + parameterPath: [ + "options", + "blobHTTPHeaders", + "blobCacheControl" + ], + mapper: { + serializedName: "x-ms-blob-cache-control", + type: { + name: "String" + } + } +}; +export const blobContentDisposition: msRest.OperationParameter = { + parameterPath: [ + "options", + "blobHTTPHeaders", + "blobContentDisposition" + ], + mapper: { + serializedName: "x-ms-blob-content-disposition", + type: { + name: "String" + } + } +}; +export const blobContentEncoding: msRest.OperationParameter = { + parameterPath: [ + "options", + "blobHTTPHeaders", + "blobContentEncoding" + ], + mapper: { + serializedName: "x-ms-blob-content-encoding", + type: { + name: "String" + } + } +}; +export const blobContentLanguage: msRest.OperationParameter = { + parameterPath: [ + "options", + "blobHTTPHeaders", + "blobContentLanguage" + ], + mapper: { + serializedName: "x-ms-blob-content-language", + type: { + name: "String" + } + } +}; +export const blobContentLength: msRest.OperationParameter = { + parameterPath: "blobContentLength", + mapper: { + required: true, + serializedName: "x-ms-blob-content-length", + type: { + name: "Number" + } + } +}; +export const blobContentMD5: msRest.OperationParameter = { + parameterPath: [ + "options", + "blobHTTPHeaders", + "blobContentMD5" + ], + mapper: { + serializedName: "x-ms-blob-content-md5", + type: { + name: "ByteArray" + } + } +}; +export const blobContentType: msRest.OperationParameter = { + parameterPath: [ + "options", + "blobHTTPHeaders", + "blobContentType" + ], + mapper: { + serializedName: "x-ms-blob-content-type", + type: { + name: "String" + } + } +}; +export const blobDeleteType: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "blobDeleteType" + ], + mapper: { + serializedName: "deletetype", + type: { + name: "Enum", + allowedValues: [ + "Permanent" + ] + } + } +}; +export const blobSequenceNumber: msRest.OperationParameter = { + parameterPath: [ + "options", + "blobSequenceNumber" + ], + mapper: { + serializedName: "x-ms-blob-sequence-number", + defaultValue: 0, + type: { + name: "Number" + } + } +}; +export const blobTagsString: msRest.OperationParameter = { + parameterPath: [ + "options", + "blobTagsString" + ], + mapper: { + serializedName: "x-ms-tags", + type: { + name: "String" + } + } +}; +export const blobType0: msRest.OperationParameter = { + parameterPath: "blobType", + mapper: { + required: true, + isConstant: true, + serializedName: "x-ms-blob-type", + defaultValue: 'PageBlob', + type: { + name: "String" + } + } +}; +export const blobType1: msRest.OperationParameter = { + parameterPath: "blobType", + mapper: { + required: true, + isConstant: true, + serializedName: "x-ms-blob-type", + defaultValue: 'AppendBlob', + type: { + name: "String" + } + } +}; +export const blobType2: msRest.OperationParameter = { + parameterPath: "blobType", + mapper: { + required: true, + isConstant: true, + serializedName: "x-ms-blob-type", + defaultValue: 'BlockBlob', + type: { + name: "String" + } + } +}; +export const blockId: msRest.OperationQueryParameter = { + parameterPath: "blockId", + mapper: { + required: true, + serializedName: "blockid", + type: { + name: "String" + } + } +}; +export const breakPeriod: msRest.OperationParameter = { + parameterPath: [ + "options", + "breakPeriod" + ], + mapper: { + serializedName: "x-ms-lease-break-period", + type: { + name: "Number" + } + } +}; +export const cacheControl: msRest.OperationParameter = { + parameterPath: [ + "options", + "pathHTTPHeaders", + "cacheControl" + ], + mapper: { + serializedName: "x-ms-cache-control", + type: { + name: "String" + } + } +}; +export const close: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "close" + ], + mapper: { + serializedName: "close", + type: { + name: "Boolean" + } + } +}; +export const comp0: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'properties', + type: { + name: "String" + } + } +}; +export const comp1: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'stats', + type: { + name: "String" + } + } +}; +export const comp10: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'lease', + type: { + name: "String" + } + } +}; +export const comp11: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'page', + type: { + name: "String" + } + } +}; +export const comp12: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'pagelist', + type: { + name: "String" + } + } +}; +export const comp13: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'incrementalcopy', + type: { + name: "String" + } + } +}; +export const comp14: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'appendblock', + type: { + name: "String" + } + } +}; +export const comp15: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'seal', + type: { + name: "String" + } + } +}; +export const comp16: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'block', + type: { + name: "String" + } + } +}; +export const comp17: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'blocklist', + type: { + name: "String" + } + } +}; +export const comp18: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'immutabilityPolicies', + type: { + name: "String" + } + } +}; +export const comp19: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'legalhold', + type: { + name: "String" + } + } +}; +export const comp2: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'list', + type: { + name: "String" + } + } +}; +export const comp20: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'snapshot', + type: { + name: "String" + } + } +}; +export const comp21: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'copy', + type: { + name: "String" + } + } +}; +export const comp22: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'tier', + type: { + name: "String" + } + } +}; +export const comp23: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'query', + type: { + name: "String" + } + } +}; +export const comp24: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'tags', + type: { + name: "String" + } + } +}; +export const comp3: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'userdelegationkey', + type: { + name: "String" + } + } +}; +export const comp4: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'batch', + type: { + name: "String" + } + } +}; +export const comp5: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'blobs', + type: { + name: "String" + } + } +}; +export const comp6: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'expiry', + type: { + name: "String" + } + } +}; +export const comp7: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'undelete', + type: { + name: "String" + } + } +}; +export const comp8: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'metadata', + type: { + name: "String" + } + } +}; +export const comp9: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'acl', + type: { + name: "String" + } + } +}; +export const contentDisposition: msRest.OperationParameter = { + parameterPath: [ + "options", + "pathHTTPHeaders", + "contentDisposition" + ], + mapper: { + serializedName: "x-ms-content-disposition", + type: { + name: "String" + } + } +}; +export const contentEncoding: msRest.OperationParameter = { + parameterPath: [ + "options", + "pathHTTPHeaders", + "contentEncoding" + ], + mapper: { + serializedName: "x-ms-content-encoding", + type: { + name: "String" + } + } +}; +export const contentLanguage: msRest.OperationParameter = { + parameterPath: [ + "options", + "pathHTTPHeaders", + "contentLanguage" + ], + mapper: { + serializedName: "x-ms-content-language", + type: { + name: "String" + } + } +}; +export const contentLength0: msRest.OperationParameter = { + parameterPath: "contentLength", + mapper: { + required: true, + serializedName: "Content-Length", + type: { + name: "Number" + } + } +}; +export const contentLength1: msRest.OperationParameter = { + parameterPath: [ + "options", + "contentLength" + ], + mapper: { + serializedName: "Content-Length", + constraints: { + InclusiveMinimum: 0 + }, + type: { + name: "Number" + } + } +}; +export const contentMD5: msRest.OperationParameter = { + parameterPath: [ + "options", + "pathHTTPHeaders", + "contentMD5" + ], + mapper: { + serializedName: "x-ms-content-md5", + type: { + name: "ByteArray" + } + } +}; +export const contentType: msRest.OperationParameter = { + parameterPath: [ + "options", + "pathHTTPHeaders", + "contentType" + ], + mapper: { + serializedName: "x-ms-content-type", + type: { + name: "String" + } + } +}; +export const continuation: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "continuation" + ], + mapper: { + serializedName: "continuation", + type: { + name: "String" + } + } +}; +export const copyActionAbortConstant: msRest.OperationParameter = { + parameterPath: "copyActionAbortConstant", + mapper: { + required: true, + isConstant: true, + serializedName: "x-ms-copy-action", + defaultValue: 'abort', + type: { + name: "String" + } + } +}; +export const copyId: msRest.OperationQueryParameter = { + parameterPath: "copyId", + mapper: { + required: true, + serializedName: "copyid", + type: { + name: "String" + } + } +}; +export const copySource: msRest.OperationParameter = { + parameterPath: "copySource", + mapper: { + required: true, + serializedName: "x-ms-copy-source", + type: { + name: "String" + } + } +}; +export const copySourceAuthorization: msRest.OperationParameter = { + parameterPath: [ + "options", + "copySourceAuthorization" + ], + mapper: { + serializedName: "x-ms-copy-source-authorization", + type: { + name: "String" + } + } +}; +export const copySourceBlobProperties: msRest.OperationParameter = { + parameterPath: [ + "options", + "copySourceBlobProperties" + ], + mapper: { + serializedName: "x-ms-copy-source-blob-properties", + type: { + name: "Boolean" + } + } +}; +export const copySourceTags: msRest.OperationParameter = { + parameterPath: [ + "options", + "copySourceTags" + ], + mapper: { + serializedName: "x-ms-copy-source-tag-option", + type: { + name: "Enum", + allowedValues: [ + "REPLACE", + "COPY" + ] + } + } +}; +export const defaultEncryptionScope: msRest.OperationParameter = { + parameterPath: [ + "options", + "containerCpkScopeInfo", + "defaultEncryptionScope" + ], + mapper: { + serializedName: "x-ms-default-encryption-scope", + type: { + name: "String" + } + } +}; +export const deletedContainerName: msRest.OperationParameter = { + parameterPath: [ + "options", + "deletedContainerName" + ], + mapper: { + serializedName: "x-ms-deleted-container-name", + type: { + name: "String" + } + } +}; +export const deletedContainerVersion: msRest.OperationParameter = { + parameterPath: [ + "options", + "deletedContainerVersion" + ], + mapper: { + serializedName: "x-ms-deleted-container-version", + type: { + name: "String" + } + } +}; +export const deleteSnapshots: msRest.OperationParameter = { + parameterPath: [ + "options", + "deleteSnapshots" + ], + mapper: { + serializedName: "x-ms-delete-snapshots", + type: { + name: "Enum", + allowedValues: [ + "include", + "only" + ] + } + } +}; +export const delimiter: msRest.OperationQueryParameter = { + parameterPath: "delimiter", + mapper: { + required: true, + serializedName: "delimiter", + type: { + name: "String" + } + } +}; +export const duration: msRest.OperationParameter = { + parameterPath: [ + "options", + "duration" + ], + mapper: { + serializedName: "x-ms-lease-duration", + type: { + name: "Number" + } + } +}; +export const encryptionAlgorithm: msRest.OperationParameter = { + parameterPath: [ + "options", + "cpkInfo", + "encryptionAlgorithm" + ], + mapper: { + serializedName: "x-ms-encryption-algorithm", + type: { + name: "Enum", + allowedValues: [ + "AES256" + ] + } + } +}; +export const encryptionKey: msRest.OperationParameter = { + parameterPath: [ + "options", + "cpkInfo", + "encryptionKey" + ], + mapper: { + serializedName: "x-ms-encryption-key", + type: { + name: "String" + } + } +}; +export const encryptionKeySha256: msRest.OperationParameter = { + parameterPath: [ + "options", + "cpkInfo", + "encryptionKeySha256" + ], + mapper: { + serializedName: "x-ms-encryption-key-sha256", + type: { + name: "String" + } + } +}; +export const encryptionScope: msRest.OperationParameter = { + parameterPath: [ + "options", + "cpkScopeInfo", + "encryptionScope" + ], + mapper: { + serializedName: "x-ms-encryption-scope", + type: { + name: "String" + } + } +}; +export const expiresOn: msRest.OperationParameter = { + parameterPath: [ + "options", + "expiresOn" + ], + mapper: { + serializedName: "x-ms-expiry-time", + type: { + name: "String" + } + } +}; +export const expiryOptions0: msRest.OperationParameter = { + parameterPath: [ + "options", + "expiryOptions" + ], + mapper: { + serializedName: "x-ms-expiry-option", + type: { + name: "String" + } + } +}; +export const expiryOptions1: msRest.OperationParameter = { + parameterPath: "expiryOptions", + mapper: { + required: true, + serializedName: "x-ms-expiry-option", + type: { + name: "String" + } + } +}; +export const fileSystem: msRest.OperationURLParameter = { + parameterPath: "fileSystem", + mapper: { + required: true, + serializedName: "filesystem", + constraints: { + MaxLength: 63, + MinLength: 3, + Pattern: /^[$a-z0-9](?!.*--)[-a-z0-9]{1,61}[a-z0-9]$/ + }, + type: { + name: "String" + } + } +}; +export const flush: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "flush" + ], + mapper: { + serializedName: "flush", + type: { + name: "Boolean" + } + } +}; +export const forceFlag: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "forceFlag" + ], + mapper: { + serializedName: "forceFlag", + type: { + name: "Boolean" + } + } +}; +export const group: msRest.OperationParameter = { + parameterPath: [ + "options", + "group" + ], + mapper: { + serializedName: "x-ms-group", + type: { + name: "String" + } + } +}; +export const ifMatch: msRest.OperationParameter = { + parameterPath: [ + "options", + "modifiedAccessConditions", + "ifMatch" + ], + mapper: { + serializedName: "If-Match", + type: { + name: "String" + } + } +}; +export const ifModifiedSince: msRest.OperationParameter = { + parameterPath: [ + "options", + "modifiedAccessConditions", + "ifModifiedSince" + ], + mapper: { + serializedName: "If-Modified-Since", + type: { + name: "DateTimeRfc1123" + } + } +}; +export const ifNoneMatch: msRest.OperationParameter = { + parameterPath: [ + "options", + "modifiedAccessConditions", + "ifNoneMatch" + ], + mapper: { + serializedName: "If-None-Match", + type: { + name: "String" + } + } +}; +export const ifSequenceNumberEqualTo: msRest.OperationParameter = { + parameterPath: [ + "options", + "sequenceNumberAccessConditions", + "ifSequenceNumberEqualTo" + ], + mapper: { + serializedName: "x-ms-if-sequence-number-eq", + type: { + name: "Number" + } + } +}; +export const ifSequenceNumberLessThan: msRest.OperationParameter = { + parameterPath: [ + "options", + "sequenceNumberAccessConditions", + "ifSequenceNumberLessThan" + ], + mapper: { + serializedName: "x-ms-if-sequence-number-lt", + type: { + name: "Number" + } + } +}; +export const ifSequenceNumberLessThanOrEqualTo: msRest.OperationParameter = { + parameterPath: [ + "options", + "sequenceNumberAccessConditions", + "ifSequenceNumberLessThanOrEqualTo" + ], + mapper: { + serializedName: "x-ms-if-sequence-number-le", + type: { + name: "Number" + } + } +}; +export const ifTags: msRest.OperationParameter = { + parameterPath: [ + "options", + "modifiedAccessConditions", + "ifTags" + ], + mapper: { + serializedName: "x-ms-if-tags", + type: { + name: "String" + } + } +}; +export const ifUnmodifiedSince: msRest.OperationParameter = { + parameterPath: [ + "options", + "modifiedAccessConditions", + "ifUnmodifiedSince" + ], + mapper: { + serializedName: "If-Unmodified-Since", + type: { + name: "DateTimeRfc1123" + } + } +}; +export const immutabilityPolicyExpiry: msRest.OperationParameter = { + parameterPath: [ + "options", + "immutabilityPolicyExpiry" + ], + mapper: { + serializedName: "x-ms-immutability-policy-until-date", + type: { + name: "DateTimeRfc1123" + } + } +}; +export const immutabilityPolicyMode: msRest.OperationParameter = { + parameterPath: [ + "options", + "immutabilityPolicyMode" + ], + mapper: { + serializedName: "x-ms-immutability-policy-mode", + type: { + name: "Enum", + allowedValues: [ + "Mutable", + "Unlocked", + "Locked" + ] + } + } +}; +export const include0: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "include" + ], + mapper: { + serializedName: "include", + type: { + name: "Sequence", + element: { + type: { + name: "Enum", + allowedValues: [ + "", + "metadata", + "deleted", + "system" + ] + } + } + } + }, + collectionFormat: msRest.QueryCollectionFormat.Csv +}; +export const include1: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "include" + ], + mapper: { + serializedName: "include", + type: { + name: "Sequence", + element: { + type: { + name: "Enum", + allowedValues: [ + "none", + "versions" + ] + } + } + } + }, + collectionFormat: msRest.QueryCollectionFormat.Csv +}; +export const include2: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "include" + ], + mapper: { + serializedName: "include", + type: { + name: "Sequence", + element: { + type: { + name: "Enum", + allowedValues: [ + "", + "copy", + "deleted", + "metadata", + "snapshots", + "uncommittedblobs", + "versions", + "tags", + "immutabilitypolicy", + "legalhold", + "deletedwithversions", + "permissions" + ] + } + } + } + }, + collectionFormat: msRest.QueryCollectionFormat.Csv +}; +export const leaseAction: msRest.OperationParameter = { + parameterPath: [ + "options", + "leaseAction" + ], + mapper: { + serializedName: "x-ms-lease-action", + type: { + name: "Enum", + allowedValues: [ + "acquire", + "release", + "renew", + "break", + "change", + "auto-renew", + "acquire-release" + ] + } + } +}; +export const leaseDuration: msRest.OperationParameter = { + parameterPath: [ + "options", + "leaseDuration" + ], + mapper: { + serializedName: "x-ms-lease-duration", + type: { + name: "Number" + } + } +}; +export const leaseId0: msRest.OperationParameter = { + parameterPath: [ + "options", + "leaseAccessConditions", + "leaseId" + ], + mapper: { + serializedName: "x-ms-lease-id", + type: { + name: "String" + } + } +}; +export const leaseId1: msRest.OperationParameter = { + parameterPath: "leaseId", + mapper: { + required: true, + serializedName: "x-ms-lease-id", + type: { + name: "String" + } + } +}; +export const legalHold0: msRest.OperationParameter = { + parameterPath: [ + "options", + "legalHold" + ], + mapper: { + serializedName: "x-ms-legal-hold", + type: { + name: "Boolean" + } + } +}; +export const legalHold1: msRest.OperationParameter = { + parameterPath: "legalHold", + mapper: { + required: true, + serializedName: "x-ms-legal-hold", + type: { + name: "Boolean" + } + } +}; +export const listType: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "listType" + ], + mapper: { + serializedName: "blocklisttype", + defaultValue: 'committed', + type: { + name: "Enum", + allowedValues: [ + "committed", + "uncommitted", + "all" + ] + } + } +}; +export const marker: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "marker" + ], + mapper: { + serializedName: "marker", + type: { + name: "String" + } + } +}; +export const maxRecords: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "maxRecords" + ], + mapper: { + serializedName: "maxRecords", + constraints: { + InclusiveMinimum: 1 + }, + type: { + name: "Number" + } + } +}; +export const maxresults: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "maxresults" + ], + mapper: { + serializedName: "maxresults", + constraints: { + InclusiveMinimum: 1 + }, + type: { + name: "Number" + } + } +}; +export const maxResults: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "maxResults" + ], + mapper: { + serializedName: "maxResults", + constraints: { + InclusiveMinimum: 1 + }, + type: { + name: "Number" + } + } +}; +export const maxSize: msRest.OperationParameter = { + parameterPath: [ + "options", + "appendPositionAccessConditions", + "maxSize" + ], + mapper: { + serializedName: "x-ms-blob-condition-maxsize", + type: { + name: "Number" + } + } +}; +export const metadata: msRest.OperationParameter = { + parameterPath: [ + "options", + "metadata" + ], + mapper: { + serializedName: "x-ms-meta", + type: { + name: "Dictionary", + value: { + type: { + name: "String" + } + } + }, + headerCollectionPrefix: "x-ms-meta-" + } +}; +export const mode0: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "mode" + ], + mapper: { + serializedName: "mode", + type: { + name: "Enum", + allowedValues: [ + "legacy", + "posix" + ] + } + } +}; +export const mode1: msRest.OperationQueryParameter = { + parameterPath: "mode", + mapper: { + required: true, + serializedName: "mode", + type: { + name: "Enum", + allowedValues: [ + "set", + "modify", + "remove" + ] + } + } +}; +export const multipartContentType: msRest.OperationParameter = { + parameterPath: "multipartContentType", + mapper: { + required: true, + serializedName: "Content-Type", + type: { + name: "String" + } + } +}; +export const owner: msRest.OperationParameter = { + parameterPath: [ + "options", + "owner" + ], + mapper: { + serializedName: "x-ms-owner", + type: { + name: "String" + } + } +}; +export const pageWrite0: msRest.OperationParameter = { + parameterPath: "pageWrite", + mapper: { + required: true, + isConstant: true, + serializedName: "x-ms-page-write", + defaultValue: 'update', + type: { + name: "String" + } + } +}; +export const pageWrite1: msRest.OperationParameter = { + parameterPath: "pageWrite", + mapper: { + required: true, + isConstant: true, + serializedName: "x-ms-page-write", + defaultValue: 'clear', + type: { + name: "String" + } + } +}; +export const path0: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "path" + ], + mapper: { + serializedName: "directory", + type: { + name: "String" + } + } +}; +export const path1: msRest.OperationURLParameter = { + parameterPath: "path", + mapper: { + required: true, + serializedName: "path", + type: { + name: "String" + } + } +}; +export const permissions: msRest.OperationParameter = { + parameterPath: [ + "options", + "permissions" + ], + mapper: { + serializedName: "x-ms-permissions", + type: { + name: "String" + } + } +}; +export const position: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "position" + ], + mapper: { + serializedName: "position", + type: { + name: "Number" + } + } +}; +export const prefix: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "prefix" + ], + mapper: { + serializedName: "prefix", + type: { + name: "String" + } + } +}; +export const preventEncryptionScopeOverride: msRest.OperationParameter = { + parameterPath: [ + "options", + "containerCpkScopeInfo", + "preventEncryptionScopeOverride" + ], + mapper: { + serializedName: "x-ms-deny-encryption-scope-override", + type: { + name: "Boolean" + } + } +}; +export const prevsnapshot: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "prevsnapshot" + ], + mapper: { + serializedName: "prevsnapshot", + type: { + name: "String" + } + } +}; +export const prevSnapshotUrl: msRest.OperationParameter = { + parameterPath: [ + "options", + "prevSnapshotUrl" + ], + mapper: { + serializedName: "x-ms-previous-snapshot-url", + type: { + name: "String" + } + } +}; +export const properties: msRest.OperationParameter = { + parameterPath: [ + "options", + "properties" + ], + mapper: { + serializedName: "x-ms-properties", + type: { + name: "String" + } + } +}; +export const proposedLeaseId0: msRest.OperationParameter = { + parameterPath: [ + "options", + "proposedLeaseId" + ], + mapper: { + serializedName: "x-ms-proposed-lease-id", + type: { + name: "String" + } + } +}; +export const proposedLeaseId1: msRest.OperationParameter = { + parameterPath: "proposedLeaseId", + mapper: { + required: true, + serializedName: "x-ms-proposed-lease-id", + type: { + name: "String" + } + } +}; +export const range0: msRest.OperationParameter = { + parameterPath: [ + "options", + "range" + ], + mapper: { + serializedName: "x-ms-range", + type: { + name: "String" + } + } +}; +export const range1: msRest.OperationParameter = { + parameterPath: "range", + mapper: { + required: true, + serializedName: "x-ms-range", + type: { + name: "String" + } + } +}; +export const rangeGetContentCRC64: msRest.OperationParameter = { + parameterPath: [ + "options", + "rangeGetContentCRC64" + ], + mapper: { + serializedName: "x-ms-range-get-content-crc64", + type: { + name: "Boolean" + } + } +}; +export const rangeGetContentMD5: msRest.OperationParameter = { + parameterPath: [ + "options", + "rangeGetContentMD5" + ], + mapper: { + serializedName: "x-ms-range-get-content-md5", + type: { + name: "Boolean" + } + } +}; +export const recursive0: msRest.OperationQueryParameter = { + parameterPath: "recursive", + mapper: { + required: true, + serializedName: "recursive", + type: { + name: "Boolean" + } + } +}; +export const recursive1: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "recursive" + ], + mapper: { + serializedName: "recursive", + type: { + name: "Boolean" + } + } +}; +export const rehydratePriority: msRest.OperationParameter = { + parameterPath: [ + "options", + "rehydratePriority" + ], + mapper: { + serializedName: "x-ms-rehydrate-priority", + type: { + name: "String" + } + } +}; +export const renameSource: msRest.OperationParameter = { + parameterPath: [ + "options", + "renameSource" + ], + mapper: { + serializedName: "x-ms-rename-source", + type: { + name: "String" + } + } +}; +export const requestId: msRest.OperationParameter = { + parameterPath: [ + "options", + "requestId" + ], + mapper: { + serializedName: "x-ms-client-request-id", + type: { + name: "String" + } + } +}; +export const resource0: msRest.OperationQueryParameter = { + parameterPath: "resource", + mapper: { + required: true, + isConstant: true, + serializedName: "resource", + defaultValue: 'account', + type: { + name: "String" + } + } +}; +export const resource1: msRest.OperationQueryParameter = { + parameterPath: "resource", + mapper: { + required: true, + isConstant: true, + serializedName: "resource", + defaultValue: 'filesystem', + type: { + name: "String" + } + } +}; +export const resource2: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "resource" + ], + mapper: { + serializedName: "resource", + type: { + name: "Enum", + allowedValues: [ + "directory", + "file" + ] + } + } +}; +export const restype0: msRest.OperationQueryParameter = { + parameterPath: "restype", + mapper: { + required: true, + isConstant: true, + serializedName: "restype", + defaultValue: 'service', + type: { + name: "String" + } + } +}; +export const restype1: msRest.OperationQueryParameter = { + parameterPath: "restype", + mapper: { + required: true, + isConstant: true, + serializedName: "restype", + defaultValue: 'account', + type: { + name: "String" + } + } +}; +export const restype2: msRest.OperationQueryParameter = { + parameterPath: "restype", + mapper: { + required: true, + isConstant: true, + serializedName: "restype", + defaultValue: 'container', + type: { + name: "String" + } + } +}; +export const retainUncommittedData: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "retainUncommittedData" + ], + mapper: { + serializedName: "retainUncommittedData", + type: { + name: "Boolean" + } + } +}; +export const sealBlob: msRest.OperationParameter = { + parameterPath: [ + "options", + "sealBlob" + ], + mapper: { + serializedName: "x-ms-seal-blob", + type: { + name: "Boolean" + } + } +}; +export const sequenceNumberAction: msRest.OperationParameter = { + parameterPath: "sequenceNumberAction", + mapper: { + required: true, + serializedName: "x-ms-sequence-number-action", + type: { + name: "Enum", + allowedValues: [ + "max", + "update", + "increment" + ] + } + } +}; +export const showonly: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "showonly" + ], + mapper: { + serializedName: "showonly", + type: { + name: "Enum", + allowedValues: [ + "deleted" + ] + } + } +}; +export const snapshot: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "snapshot" + ], + mapper: { + serializedName: "snapshot", + type: { + name: "String" + } + } +}; +export const sourceContentcrc64: msRest.OperationParameter = { + parameterPath: [ + "options", + "sourceContentcrc64" + ], + mapper: { + serializedName: "x-ms-source-content-crc64", + type: { + name: "ByteArray" + } + } +}; +export const sourceContentMD5: msRest.OperationParameter = { + parameterPath: [ + "options", + "sourceContentMD5" + ], + mapper: { + serializedName: "x-ms-source-content-md5", + type: { + name: "ByteArray" + } + } +}; +export const sourceIfMatch: msRest.OperationParameter = { + parameterPath: [ + "options", + "sourceModifiedAccessConditions", + "sourceIfMatch" + ], + mapper: { + serializedName: "x-ms-source-if-match", + type: { + name: "String" + } + } +}; +export const sourceIfModifiedSince: msRest.OperationParameter = { + parameterPath: [ + "options", + "sourceModifiedAccessConditions", + "sourceIfModifiedSince" + ], + mapper: { + serializedName: "x-ms-source-if-modified-since", + type: { + name: "DateTimeRfc1123" + } + } +}; +export const sourceIfNoneMatch: msRest.OperationParameter = { + parameterPath: [ + "options", + "sourceModifiedAccessConditions", + "sourceIfNoneMatch" + ], + mapper: { + serializedName: "x-ms-source-if-none-match", + type: { + name: "String" + } + } +}; +export const sourceIfTags: msRest.OperationParameter = { + parameterPath: [ + "options", + "sourceModifiedAccessConditions", + "sourceIfTags" + ], + mapper: { + serializedName: "x-ms-source-if-tags", + type: { + name: "String" + } + } +}; +export const sourceIfUnmodifiedSince: msRest.OperationParameter = { + parameterPath: [ + "options", + "sourceModifiedAccessConditions", + "sourceIfUnmodifiedSince" + ], + mapper: { + serializedName: "x-ms-source-if-unmodified-since", + type: { + name: "DateTimeRfc1123" + } + } +}; +export const sourceLeaseId: msRest.OperationParameter = { + parameterPath: [ + "options", + "sourceLeaseId" + ], + mapper: { + serializedName: "x-ms-source-lease-id", + type: { + name: "String" + } + } +}; +export const sourceRange0: msRest.OperationParameter = { + parameterPath: "sourceRange", + mapper: { + required: true, + serializedName: "x-ms-source-range", + type: { + name: "String" + } + } +}; +export const sourceRange1: msRest.OperationParameter = { + parameterPath: [ + "options", + "sourceRange" + ], + mapper: { + serializedName: "x-ms-source-range", + type: { + name: "String" + } + } +}; +export const sourceUrl: msRest.OperationParameter = { + parameterPath: "sourceUrl", + mapper: { + required: true, + serializedName: "x-ms-copy-source", + type: { + name: "String" + } + } +}; +export const tier0: msRest.OperationParameter = { + parameterPath: [ + "options", + "tier" + ], + mapper: { + serializedName: "x-ms-access-tier", + type: { + name: "String" + } + } +}; +export const tier1: msRest.OperationParameter = { + parameterPath: "tier", + mapper: { + required: true, + serializedName: "x-ms-access-tier", + type: { + name: "String" + } + } +}; +export const timeout: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "timeout" + ], + mapper: { + serializedName: "timeout", + constraints: { + InclusiveMinimum: 0 + }, + type: { + name: "Number" + } + } +}; +export const transactionalContentCrc64: msRest.OperationParameter = { + parameterPath: [ + "options", + "transactionalContentCrc64" + ], + mapper: { + serializedName: "x-ms-content-crc64", + type: { + name: "ByteArray" + } + } +}; +export const transactionalContentHash: msRest.OperationParameter = { + parameterPath: [ + "options", + "pathHTTPHeaders", + "transactionalContentHash" + ], + mapper: { + serializedName: "Content-MD5", + type: { + name: "ByteArray" + } + } +}; +export const transactionalContentMD5: msRest.OperationParameter = { + parameterPath: [ + "options", + "transactionalContentMD5" + ], + mapper: { + serializedName: "Content-MD5", + type: { + name: "ByteArray" + } + } +}; +export const umask: msRest.OperationParameter = { + parameterPath: [ + "options", + "umask" + ], + mapper: { + serializedName: "x-ms-umask", + type: { + name: "String" + } + } +}; +export const undeleteSource: msRest.OperationParameter = { + parameterPath: [ + "options", + "undeleteSource" + ], + mapper: { + serializedName: "x-ms-undelete-source", + type: { + name: "String" + } + } +}; +export const upn: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "upn" + ], + mapper: { + serializedName: "upn", + type: { + name: "Boolean" + } + } +}; +export const url: msRest.OperationURLParameter = { + parameterPath: "url", + mapper: { + required: true, + serializedName: "url", + defaultValue: '', + type: { + name: "String" + } + }, + skipEncoding: true +}; +export const version: msRest.OperationParameter = { + parameterPath: "version", + mapper: { + serializedName: "x-ms-version", + type: { + name: "String" + } + } +}; +export const versionId: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "versionId" + ], + mapper: { + serializedName: "versionid", + type: { + name: "String" + } + } +}; +export const where: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "where" + ], + mapper: { + serializedName: "where", + type: { + name: "String" + } + } +}; +export const xMsLeaseAction: msRest.OperationParameter = { + parameterPath: "xMsLeaseAction", + mapper: { + required: true, + serializedName: "x-ms-lease-action", + type: { + name: "Enum", + allowedValues: [ + "acquire", + "break", + "change", + "renew", + "release" + ] + } + } +}; +export const xMsLeaseBreakPeriod: msRest.OperationParameter = { + parameterPath: [ + "options", + "xMsLeaseBreakPeriod" + ], + mapper: { + serializedName: "x-ms-lease-break-period", + type: { + name: "Number" + } + } +}; +export const xMsLeaseDuration: msRest.OperationParameter = { + parameterPath: [ + "options", + "xMsLeaseDuration" + ], + mapper: { + serializedName: "x-ms-lease-duration", + type: { + name: "Number" + } + } +}; +export const xMsRangeGetContentMd5: msRest.OperationParameter = { + parameterPath: [ + "options", + "xMsRangeGetContentMd5" + ], + mapper: { + serializedName: "x-ms-range-get-content-md5", + type: { + name: "Boolean" + } + } +}; +export const xMsRequiresSync: msRest.OperationParameter = { + parameterPath: "xMsRequiresSync", + mapper: { + required: true, + isConstant: true, + serializedName: "x-ms-requires-sync", + defaultValue: 'true', + type: { + name: "String" + } + } +}; diff --git a/src/dfs/generated/artifacts/specifications.ts b/src/dfs/generated/artifacts/specifications.ts new file mode 100644 index 000000000..0d6487ee5 --- /dev/null +++ b/src/dfs/generated/artifacts/specifications.ts @@ -0,0 +1,3378 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ +// tslint:disable:object-literal-sort-keys + +import * as msRest from "@azure/ms-rest-js"; + +import * as Mappers from "./mappers"; +import { Operation } from "./operation"; +import * as Parameters from "./parameters"; + +const serializer = new msRest.Serializer(Mappers, true); +// specifications for new method group start +const serviceListFileSystemsOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.resource0, + Parameters.prefix, + Parameters.continuation, + Parameters.maxResults, + Parameters.timeout + ], + headerParameters: [ + Parameters.requestId, + Parameters.version + ], + responses: { + 200: { + bodyMapper: Mappers.FileSystemList, + headersMapper: Mappers.ServiceListFileSystemsHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const serviceSetPropertiesOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype0, + Parameters.comp0 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId + ], + requestBody: { + parameterPath: "storageServiceProperties", + mapper: { + ...Mappers.StorageServiceProperties, + required: true + } + }, + contentType: "application/xml; charset=utf-8", + responses: { + 202: { + headersMapper: Mappers.ServiceSetPropertiesHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const serviceGetPropertiesOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype0, + Parameters.comp0 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId + ], + responses: { + 200: { + bodyMapper: Mappers.StorageServiceProperties, + headersMapper: Mappers.ServiceGetPropertiesHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const serviceGetStatisticsOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype0, + Parameters.comp1 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId + ], + responses: { + 200: { + bodyMapper: Mappers.StorageServiceStats, + headersMapper: Mappers.ServiceGetStatisticsHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const serviceListContainersSegmentOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.prefix, + Parameters.marker, + Parameters.maxresults, + Parameters.include0, + Parameters.timeout, + Parameters.comp2 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId + ], + responses: { + 200: { + bodyMapper: Mappers.ListContainersSegmentResponse, + headersMapper: Mappers.ServiceListContainersSegmentHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const serviceGetUserDelegationKeyOperationSpec: msRest.OperationSpec = { + httpMethod: "POST", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype0, + Parameters.comp3 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId + ], + requestBody: { + parameterPath: "keyInfo", + mapper: { + ...Mappers.KeyInfo, + required: true + } + }, + contentType: "application/xml; charset=utf-8", + responses: { + 200: { + bodyMapper: Mappers.UserDelegationKey, + headersMapper: Mappers.ServiceGetUserDelegationKeyHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const serviceGetAccountInfoOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.restype1, + Parameters.comp0 + ], + headerParameters: [ + Parameters.version + ], + responses: { + 200: { + headersMapper: Mappers.ServiceGetAccountInfoHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const serviceGetAccountInfoWithHeadOperationSpec: msRest.OperationSpec = { + httpMethod: "HEAD", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.restype1, + Parameters.comp0 + ], + headerParameters: [ + Parameters.version + ], + responses: { + 200: { + headersMapper: Mappers.ServiceGetAccountInfoWithHeadHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const serviceSubmitBatchOperationSpec: msRest.OperationSpec = { + httpMethod: "POST", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp4 + ], + headerParameters: [ + Parameters.contentLength0, + Parameters.multipartContentType, + Parameters.version, + Parameters.requestId + ], + requestBody: { + parameterPath: "body", + mapper: { + required: true, + serializedName: "body", + type: { + name: "Stream" + } + } + }, + contentType: "application/xml; charset=utf-8", + responses: { + 202: { + bodyMapper: { + serializedName: "Stream", + type: { + name: "Stream" + } + }, + headersMapper: Mappers.ServiceSubmitBatchHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const serviceFilterBlobsOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.where, + Parameters.marker, + Parameters.maxresults, + Parameters.include1, + Parameters.comp5 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId + ], + responses: { + 200: { + bodyMapper: Mappers.FilterBlobSegment, + headersMapper: Mappers.ServiceFilterBlobsHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +// specifications for new method group start +const fileSystemCreateOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{filesystem}", + urlParameters: [ + Parameters.url, + Parameters.fileSystem + ], + queryParameters: [ + Parameters.resource1, + Parameters.timeout + ], + headerParameters: [ + Parameters.properties, + Parameters.requestId, + Parameters.version + ], + responses: { + 201: { + headersMapper: Mappers.FileSystemCreateHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const fileSystemSetPropertiesOperationSpec: msRest.OperationSpec = { + httpMethod: "PATCH", + path: "{filesystem}", + urlParameters: [ + Parameters.url, + Parameters.fileSystem + ], + queryParameters: [ + Parameters.resource1, + Parameters.timeout + ], + headerParameters: [ + Parameters.properties, + Parameters.requestId, + Parameters.version, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince + ], + responses: { + 200: { + headersMapper: Mappers.FileSystemSetPropertiesHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const fileSystemGetPropertiesOperationSpec: msRest.OperationSpec = { + httpMethod: "HEAD", + path: "{filesystem}", + urlParameters: [ + Parameters.url, + Parameters.fileSystem + ], + queryParameters: [ + Parameters.resource1, + Parameters.timeout + ], + headerParameters: [ + Parameters.requestId, + Parameters.version + ], + responses: { + 200: { + headersMapper: Mappers.FileSystemGetPropertiesHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const fileSystemDeleteOperationSpec: msRest.OperationSpec = { + httpMethod: "DELETE", + path: "{filesystem}", + urlParameters: [ + Parameters.url, + Parameters.fileSystem + ], + queryParameters: [ + Parameters.resource1, + Parameters.timeout + ], + headerParameters: [ + Parameters.requestId, + Parameters.version, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince + ], + responses: { + 202: { + headersMapper: Mappers.FileSystemDeleteHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const fileSystemListPathsOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "{filesystem}", + urlParameters: [ + Parameters.url, + Parameters.fileSystem + ], + queryParameters: [ + Parameters.continuation, + Parameters.path0, + Parameters.recursive0, + Parameters.maxResults, + Parameters.upn, + Parameters.resource1, + Parameters.timeout + ], + headerParameters: [ + Parameters.requestId, + Parameters.version + ], + responses: { + 200: { + bodyMapper: Mappers.PathList, + headersMapper: Mappers.FileSystemListPathsHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const fileSystemListBlobFlatSegmentOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "{filesystem}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.prefix, + Parameters.marker, + Parameters.maxResults, + Parameters.maxresults, + Parameters.include2, + Parameters.timeout, + Parameters.restype2, + Parameters.comp2 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId + ], + responses: { + 200: { + bodyMapper: Mappers.ListBlobsFlatSegmentResponse, + headersMapper: Mappers.FileSystemListBlobFlatSegmentHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const fileSystemListBlobHierarchySegmentOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "{filesystem}", + urlParameters: [ + Parameters.url, + Parameters.fileSystem + ], + queryParameters: [ + Parameters.prefix, + Parameters.delimiter, + Parameters.marker, + Parameters.maxResults, + Parameters.maxresults, + Parameters.include2, + Parameters.showonly, + Parameters.timeout, + Parameters.restype2, + Parameters.comp2 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId + ], + responses: { + 200: { + bodyMapper: Mappers.ListBlobsHierarchySegmentResponse, + headersMapper: Mappers.FileSystemListBlobHierarchySegmentHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +// specifications for new method group start +const pathCreateOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{filesystem}/{path}", + urlParameters: [ + Parameters.url, + Parameters.fileSystem, + Parameters.path1 + ], + queryParameters: [ + Parameters.resource2, + Parameters.continuation, + Parameters.mode0, + Parameters.timeout + ], + headerParameters: [ + Parameters.renameSource, + Parameters.sourceLeaseId, + Parameters.properties, + Parameters.permissions, + Parameters.umask, + Parameters.owner, + Parameters.group, + Parameters.acl, + Parameters.proposedLeaseId0, + Parameters.leaseDuration, + Parameters.expiryOptions0, + Parameters.expiresOn, + Parameters.requestId, + Parameters.version, + Parameters.metadata, + Parameters.cacheControl, + Parameters.contentEncoding, + Parameters.contentLanguage, + Parameters.contentDisposition, + Parameters.contentType, + Parameters.leaseId0, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.sourceIfMatch, + Parameters.sourceIfNoneMatch, + Parameters.sourceIfModifiedSince, + Parameters.sourceIfUnmodifiedSince, + Parameters.encryptionKey, + Parameters.encryptionKeySha256, + Parameters.encryptionAlgorithm + ], + responses: { + 201: { + headersMapper: Mappers.PathCreateHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const pathUpdateOperationSpec: msRest.OperationSpec = { + httpMethod: "PATCH", + path: "{filesystem}/{path}", + urlParameters: [ + Parameters.url, + Parameters.fileSystem, + Parameters.path1 + ], + queryParameters: [ + Parameters.action0, + Parameters.flush, + Parameters.maxRecords, + Parameters.continuation, + Parameters.mode1, + Parameters.forceFlag, + Parameters.position, + Parameters.retainUncommittedData, + Parameters.close, + Parameters.timeout + ], + headerParameters: [ + Parameters.contentLength1, + Parameters.properties, + Parameters.owner, + Parameters.group, + Parameters.permissions, + Parameters.acl, + Parameters.requestId, + Parameters.version, + Parameters.metadata, + Parameters.contentMD5, + Parameters.cacheControl, + Parameters.contentType, + Parameters.contentDisposition, + Parameters.contentEncoding, + Parameters.contentLanguage, + Parameters.leaseId0, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince + ], + requestBody: { + parameterPath: "body", + mapper: { + required: true, + serializedName: "body", + type: { + name: "Stream" + } + } + }, + contentType: "application/octet-stream", + responses: { + 200: { + bodyMapper: Mappers.SetAccessControlRecursiveResponse, + headersMapper: Mappers.PathUpdateHeaders + }, + 202: { + headersMapper: Mappers.PathUpdateHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const pathLeaseOperationSpec: msRest.OperationSpec = { + httpMethod: "POST", + path: "{filesystem}/{path}", + urlParameters: [ + Parameters.url, + Parameters.fileSystem, + Parameters.path1 + ], + queryParameters: [ + Parameters.timeout + ], + headerParameters: [ + Parameters.xMsLeaseAction, + Parameters.xMsLeaseDuration, + Parameters.xMsLeaseBreakPeriod, + Parameters.proposedLeaseId0, + Parameters.requestId, + Parameters.version, + Parameters.metadata, + Parameters.leaseId0, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince + ], + responses: { + 200: { + headersMapper: Mappers.PathLeaseHeaders + }, + 201: { + headersMapper: Mappers.PathLeaseHeaders + }, + 202: { + headersMapper: Mappers.PathLeaseHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const pathReadOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "{filesystem}/{path}", + urlParameters: [ + Parameters.url, + Parameters.fileSystem, + Parameters.path1 + ], + queryParameters: [ + Parameters.snapshot, + Parameters.versionId, + Parameters.timeout + ], + headerParameters: [ + Parameters.xMsRangeGetContentMd5, + Parameters.range0, + Parameters.rangeGetContentMD5, + Parameters.rangeGetContentCRC64, + Parameters.version, + Parameters.requestId, + Parameters.metadata, + Parameters.leaseId0, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifTags, + Parameters.encryptionKey, + Parameters.encryptionKeySha256, + Parameters.encryptionAlgorithm + ], + responses: { + 200: { + bodyMapper: { + serializedName: "Stream", + type: { + name: "Stream" + } + }, + headersMapper: Mappers.PathReadHeaders + }, + 206: { + bodyMapper: { + serializedName: "Stream", + type: { + name: "Stream" + } + }, + headersMapper: Mappers.PathReadHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const pathGetPropertiesOperationSpec: msRest.OperationSpec = { + httpMethod: "HEAD", + path: "{filesystem}/{path}", + urlParameters: [ + Parameters.url, + Parameters.fileSystem, + Parameters.path1 + ], + queryParameters: [ + Parameters.action1, + Parameters.upn, + Parameters.snapshot, + Parameters.versionId, + Parameters.timeout + ], + headerParameters: [ + Parameters.version, + Parameters.requestId, + Parameters.metadata, + Parameters.leaseId0, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifTags, + Parameters.encryptionKey, + Parameters.encryptionKeySha256, + Parameters.encryptionAlgorithm + ], + responses: { + 200: { + headersMapper: Mappers.PathGetPropertiesHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const pathDeleteOperationSpec: msRest.OperationSpec = { + httpMethod: "DELETE", + path: "{filesystem}/{path}", + urlParameters: [ + Parameters.url, + Parameters.fileSystem, + Parameters.path1 + ], + queryParameters: [ + Parameters.recursive1, + Parameters.continuation, + Parameters.snapshot, + Parameters.versionId, + Parameters.timeout, + Parameters.blobDeleteType + ], + headerParameters: [ + Parameters.deleteSnapshots, + Parameters.version, + Parameters.requestId, + Parameters.metadata, + Parameters.leaseId0, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifTags + ], + responses: { + 200: { + headersMapper: Mappers.PathDeleteHeaders + }, + 202: { + headersMapper: Mappers.PathDeleteHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const pathSetAccessControlOperationSpec: msRest.OperationSpec = { + httpMethod: "PATCH", + path: "{filesystem}/{path}", + urlParameters: [ + Parameters.url, + Parameters.fileSystem, + Parameters.path1 + ], + queryParameters: [ + Parameters.timeout, + Parameters.action2 + ], + headerParameters: [ + Parameters.owner, + Parameters.group, + Parameters.permissions, + Parameters.acl, + Parameters.requestId, + Parameters.version, + Parameters.leaseId0, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince + ], + responses: { + 200: { + headersMapper: Mappers.PathSetAccessControlHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const pathSetAccessControlRecursiveOperationSpec: msRest.OperationSpec = { + httpMethod: "PATCH", + path: "{filesystem}/{path}", + urlParameters: [ + Parameters.url, + Parameters.fileSystem, + Parameters.path1 + ], + queryParameters: [ + Parameters.timeout, + Parameters.continuation, + Parameters.mode1, + Parameters.forceFlag, + Parameters.maxRecords, + Parameters.action3 + ], + headerParameters: [ + Parameters.acl, + Parameters.requestId, + Parameters.version + ], + responses: { + 200: { + bodyMapper: Mappers.SetAccessControlRecursiveResponse, + headersMapper: Mappers.PathSetAccessControlRecursiveHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const pathSetPropertiesOperationSpec: msRest.OperationSpec = { + httpMethod: "PATCH", + path: "{filesystem}/{path}", + urlParameters: [ + Parameters.url, + Parameters.fileSystem, + Parameters.path1 + ], + queryParameters: [ + Parameters.action4 + ], + headerParameters: [ + Parameters.properties, + Parameters.permissions, + Parameters.requestId, + Parameters.version, + Parameters.leaseId0, + Parameters.cacheControl, + Parameters.contentType, + Parameters.contentDisposition, + Parameters.contentEncoding, + Parameters.contentLanguage, + Parameters.contentMD5, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince + ], + responses: { + 200: { + headersMapper: Mappers.PathSetPropertiesHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const pathFlushDataOperationSpec: msRest.OperationSpec = { + httpMethod: "PATCH", + path: "{filesystem}/{path}", + urlParameters: [ + Parameters.url, + Parameters.fileSystem, + Parameters.path1 + ], + queryParameters: [ + Parameters.timeout, + Parameters.position, + Parameters.retainUncommittedData, + Parameters.close, + Parameters.action5 + ], + headerParameters: [ + Parameters.contentLength1, + Parameters.requestId, + Parameters.version, + Parameters.proposedLeaseId0, + Parameters.xMsLeaseDuration, + Parameters.leaseAction, + Parameters.contentMD5, + Parameters.cacheControl, + Parameters.contentType, + Parameters.contentDisposition, + Parameters.contentEncoding, + Parameters.contentLanguage, + Parameters.leaseId0, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.encryptionKey, + Parameters.encryptionKeySha256, + Parameters.encryptionAlgorithm + ], + responses: { + 200: { + headersMapper: Mappers.PathFlushDataHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const pathAppendDataOperationSpec: msRest.OperationSpec = { + httpMethod: "PATCH", + path: "{filesystem}/{path}", + urlParameters: [ + Parameters.url, + Parameters.fileSystem, + Parameters.path1 + ], + queryParameters: [ + Parameters.position, + Parameters.timeout, + Parameters.flush, + Parameters.action6 + ], + headerParameters: [ + Parameters.contentLength1, + Parameters.transactionalContentCrc64, + Parameters.requestId, + Parameters.version, + Parameters.proposedLeaseId0, + Parameters.xMsLeaseDuration, + Parameters.leaseAction, + Parameters.transactionalContentHash, + Parameters.leaseId0, + Parameters.encryptionKey, + Parameters.encryptionKeySha256, + Parameters.encryptionAlgorithm, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince + ], + requestBody: { + parameterPath: "body", + mapper: { + required: true, + serializedName: "body", + type: { + name: "Stream" + } + } + }, + responses: { + 202: { + headersMapper: Mappers.PathAppendDataHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const pathSetExpiryOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{filesystem}/{path}", + urlParameters: [ + Parameters.url, + Parameters.fileSystem, + Parameters.path1 + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp6 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId, + Parameters.expiryOptions1, + Parameters.expiresOn + ], + responses: { + 200: { + headersMapper: Mappers.PathSetExpiryHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const pathUndeleteOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{filesystem}/{path}", + urlParameters: [ + Parameters.url, + Parameters.fileSystem, + Parameters.path1 + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp7 + ], + headerParameters: [ + Parameters.undeleteSource, + Parameters.version, + Parameters.requestId + ], + responses: { + 200: { + headersMapper: Mappers.PathUndeleteHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +// specifications for new method group start +const containerCreateOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype2 + ], + headerParameters: [ + Parameters.metadata, + Parameters.access, + Parameters.version, + Parameters.requestId, + Parameters.defaultEncryptionScope, + Parameters.preventEncryptionScopeOverride + ], + responses: { + 201: { + headersMapper: Mappers.ContainerCreateHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const containerGetPropertiesOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "{containerName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype2 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId, + Parameters.leaseId0 + ], + responses: { + 200: { + headersMapper: Mappers.ContainerGetPropertiesHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const containerGetPropertiesWithHeadOperationSpec: msRest.OperationSpec = { + httpMethod: "HEAD", + path: "{containerName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype2 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId, + Parameters.leaseId0 + ], + responses: { + 200: { + headersMapper: Mappers.ContainerGetPropertiesWithHeadHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const containerDeleteOperationSpec: msRest.OperationSpec = { + httpMethod: "DELETE", + path: "{containerName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype2 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId, + Parameters.leaseId0, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince + ], + responses: { + 202: { + headersMapper: Mappers.ContainerDeleteHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const containerSetMetadataOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype2, + Parameters.comp8 + ], + headerParameters: [ + Parameters.metadata, + Parameters.version, + Parameters.requestId, + Parameters.leaseId0, + Parameters.ifModifiedSince + ], + responses: { + 200: { + headersMapper: Mappers.ContainerSetMetadataHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const containerGetAccessPolicyOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "{containerName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype2, + Parameters.comp9 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId, + Parameters.leaseId0 + ], + responses: { + 200: { + bodyMapper: { + xmlElementName: "SignedIdentifier", + serializedName: "SignedIdentifiers", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "SignedIdentifier" + } + } + } + }, + headersMapper: Mappers.ContainerGetAccessPolicyHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const containerSetAccessPolicyOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype2, + Parameters.comp9 + ], + headerParameters: [ + Parameters.access, + Parameters.version, + Parameters.requestId, + Parameters.leaseId0, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince + ], + requestBody: { + parameterPath: [ + "options", + "containerAcl" + ], + mapper: { + xmlName: "SignedIdentifiers", + xmlElementName: "SignedIdentifier", + serializedName: "containerAcl", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "SignedIdentifier" + } + } + } + } + }, + contentType: "application/xml; charset=utf-8", + responses: { + 200: { + headersMapper: Mappers.ContainerSetAccessPolicyHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const containerRestoreOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype2, + Parameters.comp7 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId, + Parameters.deletedContainerName, + Parameters.deletedContainerVersion + ], + responses: { + 201: { + headersMapper: Mappers.ContainerRestoreHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const containerSubmitBatchOperationSpec: msRest.OperationSpec = { + httpMethod: "POST", + path: "{containerName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype2, + Parameters.comp4 + ], + headerParameters: [ + Parameters.contentLength0, + Parameters.multipartContentType, + Parameters.version, + Parameters.requestId + ], + requestBody: { + parameterPath: "body", + mapper: { + required: true, + serializedName: "body", + type: { + name: "Stream" + } + } + }, + contentType: "application/xml; charset=utf-8", + responses: { + 202: { + bodyMapper: { + serializedName: "Stream", + type: { + name: "Stream" + } + }, + headersMapper: Mappers.ContainerSubmitBatchHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const containerFilterBlobsOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "{containerName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.where, + Parameters.marker, + Parameters.maxresults, + Parameters.include1, + Parameters.restype2, + Parameters.comp5 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId + ], + responses: { + 200: { + bodyMapper: Mappers.FilterBlobSegment, + headersMapper: Mappers.ContainerFilterBlobsHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const containerAcquireLeaseOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp10, + Parameters.restype2 + ], + headerParameters: [ + Parameters.duration, + Parameters.proposedLeaseId0, + Parameters.version, + Parameters.requestId, + Parameters.action7, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince + ], + responses: { + 201: { + headersMapper: Mappers.ContainerAcquireLeaseHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const containerReleaseLeaseOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp10, + Parameters.restype2 + ], + headerParameters: [ + Parameters.leaseId1, + Parameters.version, + Parameters.requestId, + Parameters.action8, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince + ], + responses: { + 200: { + headersMapper: Mappers.ContainerReleaseLeaseHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const containerRenewLeaseOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp10, + Parameters.restype2 + ], + headerParameters: [ + Parameters.leaseId1, + Parameters.version, + Parameters.requestId, + Parameters.action9, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince + ], + responses: { + 200: { + headersMapper: Mappers.ContainerRenewLeaseHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const containerBreakLeaseOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp10, + Parameters.restype2 + ], + headerParameters: [ + Parameters.breakPeriod, + Parameters.version, + Parameters.requestId, + Parameters.action10, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince + ], + responses: { + 202: { + headersMapper: Mappers.ContainerBreakLeaseHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const containerChangeLeaseOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp10, + Parameters.restype2 + ], + headerParameters: [ + Parameters.leaseId1, + Parameters.proposedLeaseId1, + Parameters.version, + Parameters.requestId, + Parameters.action11, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince + ], + responses: { + 200: { + headersMapper: Mappers.ContainerChangeLeaseHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const containerGetAccountInfoOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "{containerName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.restype1, + Parameters.comp0 + ], + headerParameters: [ + Parameters.version + ], + responses: { + 200: { + headersMapper: Mappers.ContainerGetAccountInfoHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const containerGetAccountInfoWithHeadOperationSpec: msRest.OperationSpec = { + httpMethod: "HEAD", + path: "{containerName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.restype1, + Parameters.comp0 + ], + headerParameters: [ + Parameters.version + ], + responses: { + 200: { + headersMapper: Mappers.ContainerGetAccountInfoWithHeadHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +// specifications for new method group start +const pageBlobCreateOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout + ], + headerParameters: [ + Parameters.contentLength0, + Parameters.tier0, + Parameters.metadata, + Parameters.blobContentLength, + Parameters.blobSequenceNumber, + Parameters.version, + Parameters.requestId, + Parameters.blobTagsString, + Parameters.immutabilityPolicyExpiry, + Parameters.immutabilityPolicyMode, + Parameters.legalHold0, + Parameters.blobType0, + Parameters.blobContentType, + Parameters.blobContentEncoding, + Parameters.blobContentLanguage, + Parameters.blobContentMD5, + Parameters.blobCacheControl, + Parameters.blobContentDisposition, + Parameters.leaseId0, + Parameters.encryptionKey, + Parameters.encryptionKeySha256, + Parameters.encryptionAlgorithm, + Parameters.encryptionScope, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags + ], + responses: { + 201: { + headersMapper: Mappers.PageBlobCreateHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const pageBlobUploadPagesOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp11 + ], + headerParameters: [ + Parameters.contentLength0, + Parameters.transactionalContentMD5, + Parameters.transactionalContentCrc64, + Parameters.range0, + Parameters.version, + Parameters.requestId, + Parameters.pageWrite0, + Parameters.leaseId0, + Parameters.encryptionKey, + Parameters.encryptionKeySha256, + Parameters.encryptionAlgorithm, + Parameters.encryptionScope, + Parameters.ifSequenceNumberLessThanOrEqualTo, + Parameters.ifSequenceNumberLessThan, + Parameters.ifSequenceNumberEqualTo, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags + ], + requestBody: { + parameterPath: "body", + mapper: { + required: true, + serializedName: "body", + type: { + name: "Stream" + } + } + }, + contentType: "application/octet-stream", + responses: { + 201: { + headersMapper: Mappers.PageBlobUploadPagesHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const pageBlobClearPagesOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp11 + ], + headerParameters: [ + Parameters.contentLength0, + Parameters.range0, + Parameters.version, + Parameters.requestId, + Parameters.pageWrite1, + Parameters.leaseId0, + Parameters.encryptionKey, + Parameters.encryptionKeySha256, + Parameters.encryptionAlgorithm, + Parameters.encryptionScope, + Parameters.ifSequenceNumberLessThanOrEqualTo, + Parameters.ifSequenceNumberLessThan, + Parameters.ifSequenceNumberEqualTo, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags + ], + responses: { + 201: { + headersMapper: Mappers.PageBlobClearPagesHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const pageBlobUploadPagesFromURLOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp11 + ], + headerParameters: [ + Parameters.sourceUrl, + Parameters.sourceRange0, + Parameters.sourceContentMD5, + Parameters.sourceContentcrc64, + Parameters.contentLength0, + Parameters.range1, + Parameters.version, + Parameters.requestId, + Parameters.copySourceAuthorization, + Parameters.pageWrite0, + Parameters.encryptionKey, + Parameters.encryptionKeySha256, + Parameters.encryptionAlgorithm, + Parameters.encryptionScope, + Parameters.leaseId0, + Parameters.ifSequenceNumberLessThanOrEqualTo, + Parameters.ifSequenceNumberLessThan, + Parameters.ifSequenceNumberEqualTo, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags, + Parameters.sourceIfModifiedSince, + Parameters.sourceIfUnmodifiedSince, + Parameters.sourceIfMatch, + Parameters.sourceIfNoneMatch + ], + responses: { + 201: { + headersMapper: Mappers.PageBlobUploadPagesFromURLHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const pageBlobGetPageRangesOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.snapshot, + Parameters.timeout, + Parameters.marker, + Parameters.maxresults, + Parameters.comp12 + ], + headerParameters: [ + Parameters.range0, + Parameters.version, + Parameters.requestId, + Parameters.leaseId0, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags + ], + responses: { + 200: { + bodyMapper: Mappers.PageList, + headersMapper: Mappers.PageBlobGetPageRangesHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const pageBlobGetPageRangesDiffOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.snapshot, + Parameters.timeout, + Parameters.prevsnapshot, + Parameters.marker, + Parameters.maxresults, + Parameters.comp12 + ], + headerParameters: [ + Parameters.prevSnapshotUrl, + Parameters.range0, + Parameters.version, + Parameters.requestId, + Parameters.leaseId0, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags + ], + responses: { + 200: { + bodyMapper: Mappers.PageList, + headersMapper: Mappers.PageBlobGetPageRangesDiffHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const pageBlobResizeOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp0 + ], + headerParameters: [ + Parameters.blobContentLength, + Parameters.version, + Parameters.requestId, + Parameters.leaseId0, + Parameters.encryptionKey, + Parameters.encryptionKeySha256, + Parameters.encryptionAlgorithm, + Parameters.encryptionScope, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags + ], + responses: { + 200: { + headersMapper: Mappers.PageBlobResizeHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const pageBlobUpdateSequenceNumberOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp0 + ], + headerParameters: [ + Parameters.sequenceNumberAction, + Parameters.blobSequenceNumber, + Parameters.version, + Parameters.requestId, + Parameters.leaseId0, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags + ], + responses: { + 200: { + headersMapper: Mappers.PageBlobUpdateSequenceNumberHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const pageBlobCopyIncrementalOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp13 + ], + headerParameters: [ + Parameters.copySource, + Parameters.version, + Parameters.requestId, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags + ], + responses: { + 202: { + headersMapper: Mappers.PageBlobCopyIncrementalHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +// specifications for new method group start +const appendBlobCreateOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout + ], + headerParameters: [ + Parameters.contentLength0, + Parameters.metadata, + Parameters.version, + Parameters.requestId, + Parameters.blobTagsString, + Parameters.immutabilityPolicyExpiry, + Parameters.immutabilityPolicyMode, + Parameters.legalHold0, + Parameters.blobType1, + Parameters.blobContentType, + Parameters.blobContentEncoding, + Parameters.blobContentLanguage, + Parameters.blobContentMD5, + Parameters.blobCacheControl, + Parameters.blobContentDisposition, + Parameters.leaseId0, + Parameters.encryptionKey, + Parameters.encryptionKeySha256, + Parameters.encryptionAlgorithm, + Parameters.encryptionScope, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags + ], + responses: { + 201: { + headersMapper: Mappers.AppendBlobCreateHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const appendBlobAppendBlockOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp14 + ], + headerParameters: [ + Parameters.contentLength0, + Parameters.transactionalContentMD5, + Parameters.transactionalContentCrc64, + Parameters.version, + Parameters.requestId, + Parameters.leaseId0, + Parameters.maxSize, + Parameters.appendPosition, + Parameters.encryptionKey, + Parameters.encryptionKeySha256, + Parameters.encryptionAlgorithm, + Parameters.encryptionScope, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags + ], + requestBody: { + parameterPath: "body", + mapper: { + required: true, + serializedName: "body", + type: { + name: "Stream" + } + } + }, + contentType: "application/octet-stream", + responses: { + 201: { + headersMapper: Mappers.AppendBlobAppendBlockHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const appendBlobAppendBlockFromUrlOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp14 + ], + headerParameters: [ + Parameters.sourceUrl, + Parameters.sourceRange1, + Parameters.sourceContentMD5, + Parameters.sourceContentcrc64, + Parameters.contentLength0, + Parameters.transactionalContentMD5, + Parameters.version, + Parameters.requestId, + Parameters.copySourceAuthorization, + Parameters.encryptionKey, + Parameters.encryptionKeySha256, + Parameters.encryptionAlgorithm, + Parameters.encryptionScope, + Parameters.leaseId0, + Parameters.maxSize, + Parameters.appendPosition, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags, + Parameters.sourceIfModifiedSince, + Parameters.sourceIfUnmodifiedSince, + Parameters.sourceIfMatch, + Parameters.sourceIfNoneMatch + ], + responses: { + 201: { + headersMapper: Mappers.AppendBlobAppendBlockFromUrlHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const appendBlobSealOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp15 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId, + Parameters.leaseId0, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.appendPosition + ], + responses: { + 200: { + headersMapper: Mappers.AppendBlobSealHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +// specifications for new method group start +const blockBlobUploadOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout + ], + headerParameters: [ + Parameters.transactionalContentMD5, + Parameters.contentLength0, + Parameters.metadata, + Parameters.tier0, + Parameters.version, + Parameters.requestId, + Parameters.blobTagsString, + Parameters.immutabilityPolicyExpiry, + Parameters.immutabilityPolicyMode, + Parameters.legalHold0, + Parameters.transactionalContentCrc64, + Parameters.blobType2, + Parameters.blobContentType, + Parameters.blobContentEncoding, + Parameters.blobContentLanguage, + Parameters.blobContentMD5, + Parameters.blobCacheControl, + Parameters.blobContentDisposition, + Parameters.leaseId0, + Parameters.encryptionKey, + Parameters.encryptionKeySha256, + Parameters.encryptionAlgorithm, + Parameters.encryptionScope, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags + ], + requestBody: { + parameterPath: "body", + mapper: { + required: true, + serializedName: "body", + type: { + name: "Stream" + } + } + }, + contentType: "application/octet-stream", + responses: { + 201: { + headersMapper: Mappers.BlockBlobUploadHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blockBlobPutBlobFromUrlOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout + ], + headerParameters: [ + Parameters.transactionalContentMD5, + Parameters.contentLength0, + Parameters.metadata, + Parameters.tier0, + Parameters.version, + Parameters.requestId, + Parameters.sourceContentMD5, + Parameters.blobTagsString, + Parameters.copySource, + Parameters.copySourceBlobProperties, + Parameters.copySourceAuthorization, + Parameters.copySourceTags, + Parameters.blobType2, + Parameters.blobContentType, + Parameters.blobContentEncoding, + Parameters.blobContentLanguage, + Parameters.blobContentMD5, + Parameters.blobCacheControl, + Parameters.blobContentDisposition, + Parameters.leaseId0, + Parameters.encryptionKey, + Parameters.encryptionKeySha256, + Parameters.encryptionAlgorithm, + Parameters.encryptionScope, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags, + Parameters.sourceIfModifiedSince, + Parameters.sourceIfUnmodifiedSince, + Parameters.sourceIfMatch, + Parameters.sourceIfNoneMatch, + Parameters.sourceIfTags + ], + responses: { + 201: { + headersMapper: Mappers.BlockBlobPutBlobFromUrlHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blockBlobStageBlockOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.blockId, + Parameters.timeout, + Parameters.comp16 + ], + headerParameters: [ + Parameters.contentLength0, + Parameters.transactionalContentMD5, + Parameters.transactionalContentCrc64, + Parameters.version, + Parameters.requestId, + Parameters.leaseId0, + Parameters.encryptionKey, + Parameters.encryptionKeySha256, + Parameters.encryptionAlgorithm, + Parameters.encryptionScope + ], + requestBody: { + parameterPath: "body", + mapper: { + required: true, + serializedName: "body", + type: { + name: "Stream" + } + } + }, + contentType: "application/octet-stream", + responses: { + 201: { + headersMapper: Mappers.BlockBlobStageBlockHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blockBlobStageBlockFromURLOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.blockId, + Parameters.timeout, + Parameters.comp16 + ], + headerParameters: [ + Parameters.contentLength0, + Parameters.sourceUrl, + Parameters.sourceRange1, + Parameters.sourceContentMD5, + Parameters.sourceContentcrc64, + Parameters.version, + Parameters.requestId, + Parameters.copySourceAuthorization, + Parameters.encryptionKey, + Parameters.encryptionKeySha256, + Parameters.encryptionAlgorithm, + Parameters.encryptionScope, + Parameters.leaseId0, + Parameters.sourceIfModifiedSince, + Parameters.sourceIfUnmodifiedSince, + Parameters.sourceIfMatch, + Parameters.sourceIfNoneMatch + ], + responses: { + 201: { + headersMapper: Mappers.BlockBlobStageBlockFromURLHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blockBlobCommitBlockListOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp17 + ], + headerParameters: [ + Parameters.transactionalContentMD5, + Parameters.transactionalContentCrc64, + Parameters.metadata, + Parameters.tier0, + Parameters.version, + Parameters.requestId, + Parameters.blobTagsString, + Parameters.immutabilityPolicyExpiry, + Parameters.immutabilityPolicyMode, + Parameters.legalHold0, + Parameters.blobCacheControl, + Parameters.blobContentType, + Parameters.blobContentEncoding, + Parameters.blobContentLanguage, + Parameters.blobContentMD5, + Parameters.blobContentDisposition, + Parameters.leaseId0, + Parameters.encryptionKey, + Parameters.encryptionKeySha256, + Parameters.encryptionAlgorithm, + Parameters.encryptionScope, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags + ], + requestBody: { + parameterPath: "blocks", + mapper: { + ...Mappers.BlockLookupList, + required: true + } + }, + contentType: "application/xml; charset=utf-8", + responses: { + 201: { + headersMapper: Mappers.BlockBlobCommitBlockListHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blockBlobGetBlockListOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.snapshot, + Parameters.listType, + Parameters.timeout, + Parameters.comp17 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId, + Parameters.leaseId0, + Parameters.ifTags + ], + responses: { + 200: { + bodyMapper: Mappers.BlockList, + headersMapper: Mappers.BlockBlobGetBlockListHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +// specifications for new method group start +const blobUndeleteOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp7 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId + ], + responses: { + 200: { + headersMapper: Mappers.BlobUndeleteHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blobSetExpiryOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp6 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId, + Parameters.expiryOptions1, + Parameters.expiresOn + ], + responses: { + 200: { + headersMapper: Mappers.BlobSetExpiryHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blobSetHTTPHeadersOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp0 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId, + Parameters.blobCacheControl, + Parameters.blobContentType, + Parameters.blobContentMD5, + Parameters.blobContentEncoding, + Parameters.blobContentLanguage, + Parameters.blobContentDisposition, + Parameters.leaseId0, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags + ], + responses: { + 200: { + headersMapper: Mappers.BlobSetHTTPHeadersHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blobSetImmutabilityPolicyOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp18 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId, + Parameters.immutabilityPolicyExpiry, + Parameters.immutabilityPolicyMode, + Parameters.ifUnmodifiedSince + ], + responses: { + 200: { + headersMapper: Mappers.BlobSetImmutabilityPolicyHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blobDeleteImmutabilityPolicyOperationSpec: msRest.OperationSpec = { + httpMethod: "DELETE", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp18 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId + ], + responses: { + 200: { + headersMapper: Mappers.BlobDeleteImmutabilityPolicyHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blobSetLegalHoldOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp19 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId, + Parameters.legalHold1 + ], + responses: { + 200: { + headersMapper: Mappers.BlobSetLegalHoldHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blobSetMetadataOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp8 + ], + headerParameters: [ + Parameters.metadata, + Parameters.version, + Parameters.requestId, + Parameters.leaseId0, + Parameters.encryptionKey, + Parameters.encryptionKeySha256, + Parameters.encryptionAlgorithm, + Parameters.encryptionScope, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags + ], + responses: { + 200: { + headersMapper: Mappers.BlobSetMetadataHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blobAcquireLeaseOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp10 + ], + headerParameters: [ + Parameters.duration, + Parameters.proposedLeaseId0, + Parameters.version, + Parameters.requestId, + Parameters.action7, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags + ], + responses: { + 201: { + headersMapper: Mappers.BlobAcquireLeaseHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blobReleaseLeaseOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp10 + ], + headerParameters: [ + Parameters.leaseId1, + Parameters.version, + Parameters.requestId, + Parameters.action8, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags + ], + responses: { + 200: { + headersMapper: Mappers.BlobReleaseLeaseHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blobRenewLeaseOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp10 + ], + headerParameters: [ + Parameters.leaseId1, + Parameters.version, + Parameters.requestId, + Parameters.action9, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags + ], + responses: { + 200: { + headersMapper: Mappers.BlobRenewLeaseHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blobChangeLeaseOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp10 + ], + headerParameters: [ + Parameters.leaseId1, + Parameters.proposedLeaseId1, + Parameters.version, + Parameters.requestId, + Parameters.action11, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags + ], + responses: { + 200: { + headersMapper: Mappers.BlobChangeLeaseHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blobBreakLeaseOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp10 + ], + headerParameters: [ + Parameters.breakPeriod, + Parameters.version, + Parameters.requestId, + Parameters.action10, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags + ], + responses: { + 202: { + headersMapper: Mappers.BlobBreakLeaseHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blobCreateSnapshotOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp20 + ], + headerParameters: [ + Parameters.metadata, + Parameters.version, + Parameters.requestId, + Parameters.encryptionKey, + Parameters.encryptionKeySha256, + Parameters.encryptionAlgorithm, + Parameters.encryptionScope, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags, + Parameters.leaseId0 + ], + responses: { + 201: { + headersMapper: Mappers.BlobCreateSnapshotHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blobStartCopyFromURLOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout + ], + headerParameters: [ + Parameters.metadata, + Parameters.tier0, + Parameters.rehydratePriority, + Parameters.copySource, + Parameters.version, + Parameters.requestId, + Parameters.blobTagsString, + Parameters.sealBlob, + Parameters.immutabilityPolicyExpiry, + Parameters.immutabilityPolicyMode, + Parameters.legalHold0, + Parameters.sourceIfModifiedSince, + Parameters.sourceIfUnmodifiedSince, + Parameters.sourceIfMatch, + Parameters.sourceIfNoneMatch, + Parameters.sourceIfTags, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags, + Parameters.leaseId0 + ], + responses: { + 202: { + headersMapper: Mappers.BlobStartCopyFromURLHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blobCopyFromURLOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout + ], + headerParameters: [ + Parameters.metadata, + Parameters.tier0, + Parameters.copySource, + Parameters.version, + Parameters.requestId, + Parameters.sourceContentMD5, + Parameters.blobTagsString, + Parameters.immutabilityPolicyExpiry, + Parameters.immutabilityPolicyMode, + Parameters.legalHold0, + Parameters.copySourceAuthorization, + Parameters.copySourceTags, + Parameters.xMsRequiresSync, + Parameters.sourceIfModifiedSince, + Parameters.sourceIfUnmodifiedSince, + Parameters.sourceIfMatch, + Parameters.sourceIfNoneMatch, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags, + Parameters.leaseId0, + Parameters.encryptionScope + ], + responses: { + 202: { + headersMapper: Mappers.BlobCopyFromURLHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blobAbortCopyFromURLOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.copyId, + Parameters.timeout, + Parameters.comp21 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId, + Parameters.copyActionAbortConstant, + Parameters.leaseId0 + ], + responses: { + 204: { + headersMapper: Mappers.BlobAbortCopyFromURLHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blobSetTierOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.snapshot, + Parameters.versionId, + Parameters.timeout, + Parameters.comp22 + ], + headerParameters: [ + Parameters.tier1, + Parameters.rehydratePriority, + Parameters.version, + Parameters.requestId, + Parameters.leaseId0, + Parameters.ifTags + ], + responses: { + 200: { + headersMapper: Mappers.BlobSetTierHeaders + }, + 202: { + headersMapper: Mappers.BlobSetTierHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blobGetAccountInfoOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.restype1, + Parameters.comp0 + ], + headerParameters: [ + Parameters.version + ], + responses: { + 200: { + headersMapper: Mappers.BlobGetAccountInfoHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blobGetAccountInfoWithHeadOperationSpec: msRest.OperationSpec = { + httpMethod: "HEAD", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.restype1, + Parameters.comp0 + ], + headerParameters: [ + Parameters.version + ], + responses: { + 200: { + headersMapper: Mappers.BlobGetAccountInfoWithHeadHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blobQueryOperationSpec: msRest.OperationSpec = { + httpMethod: "POST", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.snapshot, + Parameters.timeout, + Parameters.comp23 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId, + Parameters.leaseId0, + Parameters.encryptionKey, + Parameters.encryptionKeySha256, + Parameters.encryptionAlgorithm, + Parameters.ifModifiedSince, + Parameters.ifUnmodifiedSince, + Parameters.ifMatch, + Parameters.ifNoneMatch, + Parameters.ifTags + ], + requestBody: { + parameterPath: [ + "options", + "queryRequest" + ], + mapper: Mappers.QueryRequest + }, + contentType: "application/xml; charset=utf-8", + responses: { + 200: { + bodyMapper: { + serializedName: "Stream", + type: { + name: "Stream" + } + }, + headersMapper: Mappers.BlobQueryHeaders + }, + 206: { + bodyMapper: { + serializedName: "Stream", + type: { + name: "Stream" + } + }, + headersMapper: Mappers.BlobQueryHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blobGetTagsOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.snapshot, + Parameters.versionId, + Parameters.comp24 + ], + headerParameters: [ + Parameters.version, + Parameters.requestId, + Parameters.ifTags, + Parameters.leaseId0 + ], + responses: { + 200: { + bodyMapper: Mappers.BlobTags, + headersMapper: Mappers.BlobGetTagsHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const blobSetTagsOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{containerName}/{blob}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.versionId, + Parameters.comp24 + ], + headerParameters: [ + Parameters.version, + Parameters.transactionalContentMD5, + Parameters.transactionalContentCrc64, + Parameters.requestId, + Parameters.ifTags, + Parameters.leaseId0 + ], + requestBody: { + parameterPath: [ + "options", + "tags" + ], + mapper: Mappers.BlobTags + }, + contentType: "application/xml; charset=utf-8", + responses: { + 204: { + headersMapper: Mappers.BlobSetTagsHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const Specifications: { [key: number]: msRest.OperationSpec } = {}; +Specifications[Operation.Service_ListFileSystems] = serviceListFileSystemsOperationSpec; +Specifications[Operation.Service_SetProperties] = serviceSetPropertiesOperationSpec; +Specifications[Operation.Service_GetProperties] = serviceGetPropertiesOperationSpec; +Specifications[Operation.Service_GetStatistics] = serviceGetStatisticsOperationSpec; +Specifications[Operation.Service_ListContainersSegment] = serviceListContainersSegmentOperationSpec; +Specifications[Operation.Service_GetUserDelegationKey] = serviceGetUserDelegationKeyOperationSpec; +Specifications[Operation.Service_GetAccountInfo] = serviceGetAccountInfoOperationSpec; +Specifications[Operation.Service_GetAccountInfoWithHead] = serviceGetAccountInfoWithHeadOperationSpec; +Specifications[Operation.Service_SubmitBatch] = serviceSubmitBatchOperationSpec; +Specifications[Operation.Service_FilterBlobs] = serviceFilterBlobsOperationSpec; +Specifications[Operation.FileSystem_Create] = fileSystemCreateOperationSpec; +Specifications[Operation.FileSystem_SetProperties] = fileSystemSetPropertiesOperationSpec; +Specifications[Operation.FileSystem_GetProperties] = fileSystemGetPropertiesOperationSpec; +Specifications[Operation.FileSystem_Delete] = fileSystemDeleteOperationSpec; +Specifications[Operation.FileSystem_ListPaths] = fileSystemListPathsOperationSpec; +Specifications[Operation.FileSystem_ListBlobFlatSegment] = fileSystemListBlobFlatSegmentOperationSpec; +Specifications[Operation.FileSystem_ListBlobHierarchySegment] = fileSystemListBlobHierarchySegmentOperationSpec; +Specifications[Operation.Path_Create] = pathCreateOperationSpec; +Specifications[Operation.Path_Update] = pathUpdateOperationSpec; +Specifications[Operation.Path_Lease] = pathLeaseOperationSpec; +Specifications[Operation.Path_Read] = pathReadOperationSpec; +Specifications[Operation.Path_GetProperties] = pathGetPropertiesOperationSpec; +Specifications[Operation.Path_Delete] = pathDeleteOperationSpec; +Specifications[Operation.Path_SetAccessControl] = pathSetAccessControlOperationSpec; +Specifications[Operation.Path_SetAccessControlRecursive] = pathSetAccessControlRecursiveOperationSpec; +Specifications[Operation.Path_SetProperties] = pathSetPropertiesOperationSpec; +Specifications[Operation.Path_FlushData] = pathFlushDataOperationSpec; +Specifications[Operation.Path_AppendData] = pathAppendDataOperationSpec; +Specifications[Operation.Path_SetExpiry] = pathSetExpiryOperationSpec; +Specifications[Operation.Path_Undelete] = pathUndeleteOperationSpec; +Specifications[Operation.Container_Create] = containerCreateOperationSpec; +Specifications[Operation.Container_GetProperties] = containerGetPropertiesOperationSpec; +Specifications[Operation.Container_GetPropertiesWithHead] = containerGetPropertiesWithHeadOperationSpec; +Specifications[Operation.Container_Delete] = containerDeleteOperationSpec; +Specifications[Operation.Container_SetMetadata] = containerSetMetadataOperationSpec; +Specifications[Operation.Container_GetAccessPolicy] = containerGetAccessPolicyOperationSpec; +Specifications[Operation.Container_SetAccessPolicy] = containerSetAccessPolicyOperationSpec; +Specifications[Operation.Container_Restore] = containerRestoreOperationSpec; +Specifications[Operation.Container_SubmitBatch] = containerSubmitBatchOperationSpec; +Specifications[Operation.Container_FilterBlobs] = containerFilterBlobsOperationSpec; +Specifications[Operation.Container_AcquireLease] = containerAcquireLeaseOperationSpec; +Specifications[Operation.Container_ReleaseLease] = containerReleaseLeaseOperationSpec; +Specifications[Operation.Container_RenewLease] = containerRenewLeaseOperationSpec; +Specifications[Operation.Container_BreakLease] = containerBreakLeaseOperationSpec; +Specifications[Operation.Container_ChangeLease] = containerChangeLeaseOperationSpec; +Specifications[Operation.Container_GetAccountInfo] = containerGetAccountInfoOperationSpec; +Specifications[Operation.Container_GetAccountInfoWithHead] = containerGetAccountInfoWithHeadOperationSpec; +Specifications[Operation.PageBlob_Create] = pageBlobCreateOperationSpec; +Specifications[Operation.PageBlob_UploadPages] = pageBlobUploadPagesOperationSpec; +Specifications[Operation.PageBlob_ClearPages] = pageBlobClearPagesOperationSpec; +Specifications[Operation.PageBlob_UploadPagesFromURL] = pageBlobUploadPagesFromURLOperationSpec; +Specifications[Operation.PageBlob_GetPageRanges] = pageBlobGetPageRangesOperationSpec; +Specifications[Operation.PageBlob_GetPageRangesDiff] = pageBlobGetPageRangesDiffOperationSpec; +Specifications[Operation.PageBlob_Resize] = pageBlobResizeOperationSpec; +Specifications[Operation.PageBlob_UpdateSequenceNumber] = pageBlobUpdateSequenceNumberOperationSpec; +Specifications[Operation.PageBlob_CopyIncremental] = pageBlobCopyIncrementalOperationSpec; +Specifications[Operation.AppendBlob_Create] = appendBlobCreateOperationSpec; +Specifications[Operation.AppendBlob_AppendBlock] = appendBlobAppendBlockOperationSpec; +Specifications[Operation.AppendBlob_AppendBlockFromUrl] = appendBlobAppendBlockFromUrlOperationSpec; +Specifications[Operation.AppendBlob_Seal] = appendBlobSealOperationSpec; +Specifications[Operation.BlockBlob_Upload] = blockBlobUploadOperationSpec; +Specifications[Operation.BlockBlob_PutBlobFromUrl] = blockBlobPutBlobFromUrlOperationSpec; +Specifications[Operation.BlockBlob_StageBlock] = blockBlobStageBlockOperationSpec; +Specifications[Operation.BlockBlob_StageBlockFromURL] = blockBlobStageBlockFromURLOperationSpec; +Specifications[Operation.BlockBlob_CommitBlockList] = blockBlobCommitBlockListOperationSpec; +Specifications[Operation.BlockBlob_GetBlockList] = blockBlobGetBlockListOperationSpec; +Specifications[Operation.Blob_Undelete] = blobUndeleteOperationSpec; +Specifications[Operation.Blob_SetExpiry] = blobSetExpiryOperationSpec; +Specifications[Operation.Blob_SetHTTPHeaders] = blobSetHTTPHeadersOperationSpec; +Specifications[Operation.Blob_SetImmutabilityPolicy] = blobSetImmutabilityPolicyOperationSpec; +Specifications[Operation.Blob_DeleteImmutabilityPolicy] = blobDeleteImmutabilityPolicyOperationSpec; +Specifications[Operation.Blob_SetLegalHold] = blobSetLegalHoldOperationSpec; +Specifications[Operation.Blob_SetMetadata] = blobSetMetadataOperationSpec; +Specifications[Operation.Blob_AcquireLease] = blobAcquireLeaseOperationSpec; +Specifications[Operation.Blob_ReleaseLease] = blobReleaseLeaseOperationSpec; +Specifications[Operation.Blob_RenewLease] = blobRenewLeaseOperationSpec; +Specifications[Operation.Blob_ChangeLease] = blobChangeLeaseOperationSpec; +Specifications[Operation.Blob_BreakLease] = blobBreakLeaseOperationSpec; +Specifications[Operation.Blob_CreateSnapshot] = blobCreateSnapshotOperationSpec; +Specifications[Operation.Blob_StartCopyFromURL] = blobStartCopyFromURLOperationSpec; +Specifications[Operation.Blob_CopyFromURL] = blobCopyFromURLOperationSpec; +Specifications[Operation.Blob_AbortCopyFromURL] = blobAbortCopyFromURLOperationSpec; +Specifications[Operation.Blob_SetTier] = blobSetTierOperationSpec; +Specifications[Operation.Blob_GetAccountInfo] = blobGetAccountInfoOperationSpec; +Specifications[Operation.Blob_GetAccountInfoWithHead] = blobGetAccountInfoWithHeadOperationSpec; +Specifications[Operation.Blob_Query] = blobQueryOperationSpec; +Specifications[Operation.Blob_GetTags] = blobGetTagsOperationSpec; +Specifications[Operation.Blob_SetTags] = blobSetTagsOperationSpec; +export default Specifications; diff --git a/src/dfs/generated/handlers/IAppendBlobHandler.ts b/src/dfs/generated/handlers/IAppendBlobHandler.ts new file mode 100644 index 000000000..8a8a17f8b --- /dev/null +++ b/src/dfs/generated/handlers/IAppendBlobHandler.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ +// tslint:disable:max-line-length + +import * as Models from "../artifacts/models"; +import Context from "../../../blob/generated/Context"; + +export default interface IAppendBlobHandler { + create(contentLength: number, options: Models.AppendBlobCreateOptionalParams, context: Context): Promise; + appendBlock(body: NodeJS.ReadableStream, contentLength: number, options: Models.AppendBlobAppendBlockOptionalParams, context: Context): Promise; + appendBlockFromUrl(sourceUrl: string, contentLength: number, options: Models.AppendBlobAppendBlockFromUrlOptionalParams, context: Context): Promise; + seal(options: Models.AppendBlobSealOptionalParams, context: Context): Promise; +} diff --git a/src/dfs/generated/handlers/IBlobHandler.ts b/src/dfs/generated/handlers/IBlobHandler.ts new file mode 100644 index 000000000..8f67f86d3 --- /dev/null +++ b/src/dfs/generated/handlers/IBlobHandler.ts @@ -0,0 +1,38 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ +// tslint:disable:max-line-length + +import * as Models from "../artifacts/models"; +import Context from "../../../blob/generated/Context"; + +export default interface IBlobHandler { + undelete(options: Models.BlobUndeleteOptionalParams, context: Context): Promise; + setExpiry(expiryOptions: Models.BlobExpiryOptions, options: Models.BlobSetExpiryOptionalParams, context: Context): Promise; + setHTTPHeaders(options: Models.BlobSetHTTPHeadersOptionalParams, context: Context): Promise; + setImmutabilityPolicy(options: Models.BlobSetImmutabilityPolicyOptionalParams, context: Context): Promise; + deleteImmutabilityPolicy(options: Models.BlobDeleteImmutabilityPolicyOptionalParams, context: Context): Promise; + setLegalHold(legalHold: boolean, options: Models.BlobSetLegalHoldOptionalParams, context: Context): Promise; + setMetadata(options: Models.BlobSetMetadataOptionalParams, context: Context): Promise; + acquireLease(options: Models.BlobAcquireLeaseOptionalParams, context: Context): Promise; + releaseLease(leaseId: string, options: Models.BlobReleaseLeaseOptionalParams, context: Context): Promise; + renewLease(leaseId: string, options: Models.BlobRenewLeaseOptionalParams, context: Context): Promise; + changeLease(leaseId: string, proposedLeaseId: string, options: Models.BlobChangeLeaseOptionalParams, context: Context): Promise; + breakLease(options: Models.BlobBreakLeaseOptionalParams, context: Context): Promise; + createSnapshot(options: Models.BlobCreateSnapshotOptionalParams, context: Context): Promise; + startCopyFromURL(copySource: string, options: Models.BlobStartCopyFromURLOptionalParams, context: Context): Promise; + copyFromURL(copySource: string, options: Models.BlobCopyFromURLOptionalParams, context: Context): Promise; + abortCopyFromURL(copyId: string, options: Models.BlobAbortCopyFromURLOptionalParams, context: Context): Promise; + setTier(tier: Models.AccessTier, options: Models.BlobSetTierOptionalParams, context: Context): Promise; + getAccountInfo(context: Context): Promise; + getAccountInfoWithHead(context: Context): Promise; + query(options: Models.BlobQueryOptionalParams, context: Context): Promise; + getTags(options: Models.BlobGetTagsOptionalParams, context: Context): Promise; + setTags(options: Models.BlobSetTagsOptionalParams, context: Context): Promise; +} diff --git a/src/dfs/generated/handlers/IBlockBlobHandler.ts b/src/dfs/generated/handlers/IBlockBlobHandler.ts new file mode 100644 index 000000000..1d41815a2 --- /dev/null +++ b/src/dfs/generated/handlers/IBlockBlobHandler.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ +// tslint:disable:max-line-length + +import * as Models from "../artifacts/models"; +import Context from "../../../blob/generated/Context"; + +export default interface IBlockBlobHandler { + upload(body: NodeJS.ReadableStream, contentLength: number, options: Models.BlockBlobUploadOptionalParams, context: Context): Promise; + putBlobFromUrl(contentLength: number, copySource: string, options: Models.BlockBlobPutBlobFromUrlOptionalParams, context: Context): Promise; + stageBlock(blockId: string, contentLength: number, body: NodeJS.ReadableStream, options: Models.BlockBlobStageBlockOptionalParams, context: Context): Promise; + stageBlockFromURL(blockId: string, contentLength: number, sourceUrl: string, options: Models.BlockBlobStageBlockFromURLOptionalParams, context: Context): Promise; + commitBlockList(blocks: Models.BlockLookupList, options: Models.BlockBlobCommitBlockListOptionalParams, context: Context): Promise; + getBlockList(options: Models.BlockBlobGetBlockListOptionalParams, context: Context): Promise; +} diff --git a/src/dfs/generated/handlers/IContainerHandler.ts b/src/dfs/generated/handlers/IContainerHandler.ts new file mode 100644 index 000000000..cd4a77e13 --- /dev/null +++ b/src/dfs/generated/handlers/IContainerHandler.ts @@ -0,0 +1,33 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ +// tslint:disable:max-line-length + +import * as Models from "../artifacts/models"; +import Context from "../../../blob/generated/Context"; + +export default interface IContainerHandler { + create(options: Models.ContainerCreateOptionalParams, context: Context): Promise; + getProperties(options: Models.ContainerGetPropertiesOptionalParams, context: Context): Promise; + getPropertiesWithHead(options: Models.ContainerGetPropertiesWithHeadOptionalParams, context: Context): Promise; + delete(options: Models.ContainerDeleteMethodOptionalParams, context: Context): Promise; + setMetadata(options: Models.ContainerSetMetadataOptionalParams, context: Context): Promise; + getAccessPolicy(options: Models.ContainerGetAccessPolicyOptionalParams, context: Context): Promise; + setAccessPolicy(options: Models.ContainerSetAccessPolicyOptionalParams, context: Context): Promise; + restore(options: Models.ContainerRestoreOptionalParams, context: Context): Promise; + submitBatch(body: NodeJS.ReadableStream, contentLength: number, multipartContentType: string, options: Models.ContainerSubmitBatchOptionalParams, context: Context): Promise; + filterBlobs(options: Models.ContainerFilterBlobsOptionalParams, context: Context): Promise; + acquireLease(options: Models.ContainerAcquireLeaseOptionalParams, context: Context): Promise; + releaseLease(leaseId: string, options: Models.ContainerReleaseLeaseOptionalParams, context: Context): Promise; + renewLease(leaseId: string, options: Models.ContainerRenewLeaseOptionalParams, context: Context): Promise; + breakLease(options: Models.ContainerBreakLeaseOptionalParams, context: Context): Promise; + changeLease(leaseId: string, proposedLeaseId: string, options: Models.ContainerChangeLeaseOptionalParams, context: Context): Promise; + getAccountInfo(context: Context): Promise; + getAccountInfoWithHead(context: Context): Promise; +} diff --git a/src/dfs/generated/handlers/IFileSystemOperationsHandler.ts b/src/dfs/generated/handlers/IFileSystemOperationsHandler.ts new file mode 100644 index 000000000..400113c34 --- /dev/null +++ b/src/dfs/generated/handlers/IFileSystemOperationsHandler.ts @@ -0,0 +1,23 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ +// tslint:disable:max-line-length + +import * as Models from "../artifacts/models"; +import Context from "../../../blob/generated/Context"; + +export default interface IFileSystemOperationsHandler { + create(options: Models.FileSystemCreateOptionalParams, context: Context): Promise; + setProperties(options: Models.FileSystemSetPropertiesOptionalParams, context: Context): Promise; + getProperties(options: Models.FileSystemGetPropertiesOptionalParams, context: Context): Promise; + delete(options: Models.FileSystemDeleteMethodOptionalParams, context: Context): Promise; + listPaths(recursive: boolean, options: Models.FileSystemListPathsOptionalParams, context: Context): Promise; + listBlobFlatSegment(options: Models.FileSystemListBlobFlatSegmentOptionalParams, context: Context): Promise; + listBlobHierarchySegment(delimiter: string, options: Models.FileSystemListBlobHierarchySegmentOptionalParams, context: Context): Promise; +} diff --git a/src/dfs/generated/handlers/IHandlers.ts b/src/dfs/generated/handlers/IHandlers.ts new file mode 100644 index 000000000..c534178d0 --- /dev/null +++ b/src/dfs/generated/handlers/IHandlers.ts @@ -0,0 +1,21 @@ +// tslint:disable:ordered-imports +import IServiceHandler from "./IServiceHandler"; +import IFileSystemOperationsHandler from "./IFileSystemOperationsHandler"; +import IPathOperationsHandler from "./IPathOperationsHandler"; +import IContainerHandler from "./IContainerHandler"; +import IPageBlobHandler from "./IPageBlobHandler"; +import IAppendBlobHandler from "./IAppendBlobHandler"; +import IBlockBlobHandler from "./IBlockBlobHandler"; +import IBlobHandler from "./IBlobHandler"; + +export interface IHandlers { + serviceHandler: IServiceHandler; + fileSystemOperationsHandler: IFileSystemOperationsHandler; + pathOperationsHandler: IPathOperationsHandler; + containerHandler: IContainerHandler; + pageBlobHandler: IPageBlobHandler; + appendBlobHandler: IAppendBlobHandler; + blockBlobHandler: IBlockBlobHandler; + blobHandler: IBlobHandler; +} +export default IHandlers; diff --git a/src/dfs/generated/handlers/IPageBlobHandler.ts b/src/dfs/generated/handlers/IPageBlobHandler.ts new file mode 100644 index 000000000..b53f67cb0 --- /dev/null +++ b/src/dfs/generated/handlers/IPageBlobHandler.ts @@ -0,0 +1,25 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ +// tslint:disable:max-line-length + +import * as Models from "../artifacts/models"; +import Context from "../../../blob/generated/Context"; + +export default interface IPageBlobHandler { + create(contentLength: number, blobContentLength: number, options: Models.PageBlobCreateOptionalParams, context: Context): Promise; + uploadPages(body: NodeJS.ReadableStream, contentLength: number, options: Models.PageBlobUploadPagesOptionalParams, context: Context): Promise; + clearPages(contentLength: number, options: Models.PageBlobClearPagesOptionalParams, context: Context): Promise; + uploadPagesFromURL(sourceUrl: string, sourceRange: string, contentLength: number, range: string, options: Models.PageBlobUploadPagesFromURLOptionalParams, context: Context): Promise; + getPageRanges(options: Models.PageBlobGetPageRangesOptionalParams, context: Context): Promise; + getPageRangesDiff(options: Models.PageBlobGetPageRangesDiffOptionalParams, context: Context): Promise; + resize(blobContentLength: number, options: Models.PageBlobResizeOptionalParams, context: Context): Promise; + updateSequenceNumber(sequenceNumberAction: Models.SequenceNumberActionType, options: Models.PageBlobUpdateSequenceNumberOptionalParams, context: Context): Promise; + copyIncremental(copySource: string, options: Models.PageBlobCopyIncrementalOptionalParams, context: Context): Promise; +} diff --git a/src/dfs/generated/handlers/IPathOperationsHandler.ts b/src/dfs/generated/handlers/IPathOperationsHandler.ts new file mode 100644 index 000000000..a835875ec --- /dev/null +++ b/src/dfs/generated/handlers/IPathOperationsHandler.ts @@ -0,0 +1,29 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ +// tslint:disable:max-line-length + +import * as Models from "../artifacts/models"; +import Context from "../../../blob/generated/Context"; + +export default interface IPathOperationsHandler { + create(options: Models.PathCreateOptionalParams, context: Context): Promise; + update(action: Models.PathUpdateAction, mode: Models.PathSetAccessControlRecursiveMode, body: NodeJS.ReadableStream, options: Models.PathUpdateOptionalParams, context: Context): Promise; + lease(xMsLeaseAction: Models.PathLeaseAction, options: Models.PathLeaseOptionalParams, context: Context): Promise; + read(options: Models.PathReadOptionalParams, context: Context): Promise; + getProperties(options: Models.PathGetPropertiesOptionalParams, context: Context): Promise; + delete(options: Models.PathDeleteMethodOptionalParams, context: Context): Promise; + setAccessControl(options: Models.PathSetAccessControlOptionalParams, context: Context): Promise; + setAccessControlRecursive(mode: Models.PathSetAccessControlRecursiveMode, options: Models.PathSetAccessControlRecursiveOptionalParams, context: Context): Promise; + setProperties(options: Models.PathSetPropertiesOptionalParams, context: Context): Promise; + flushData(options: Models.PathFlushDataOptionalParams, context: Context): Promise; + appendData(body: NodeJS.ReadableStream, options: Models.PathAppendDataOptionalParams, context: Context): Promise; + setExpiry(expiryOptions: Models.PathExpiryOptions, options: Models.PathSetExpiryOptionalParams, context: Context): Promise; + undelete(options: Models.PathUndeleteOptionalParams, context: Context): Promise; +} diff --git a/src/dfs/generated/handlers/IServiceHandler.ts b/src/dfs/generated/handlers/IServiceHandler.ts new file mode 100644 index 000000000..3e18a8722 --- /dev/null +++ b/src/dfs/generated/handlers/IServiceHandler.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ +// tslint:disable:max-line-length + +import * as Models from "../artifacts/models"; +import Context from "../../../blob/generated/Context"; + +export default interface IServiceHandler { + listFileSystems(options: Models.ServiceListFileSystemsOptionalParams, context: Context): Promise; + setProperties(storageServiceProperties: Models.StorageServiceProperties, options: Models.ServiceSetPropertiesOptionalParams, context: Context): Promise; + getProperties(options: Models.ServiceGetPropertiesOptionalParams, context: Context): Promise; + getStatistics(options: Models.ServiceGetStatisticsOptionalParams, context: Context): Promise; + listContainersSegment(options: Models.ServiceListContainersSegmentOptionalParams, context: Context): Promise; + getUserDelegationKey(keyInfo: Models.KeyInfo, options: Models.ServiceGetUserDelegationKeyOptionalParams, context: Context): Promise; + getAccountInfo(context: Context): Promise; + getAccountInfoWithHead(context: Context): Promise; + submitBatch(body: NodeJS.ReadableStream, contentLength: number, multipartContentType: string, options: Models.ServiceSubmitBatchOptionalParams, context: Context): Promise; + filterBlobs(options: Models.ServiceFilterBlobsOptionalParams, context: Context): Promise; +} diff --git a/src/dfs/generated/handlers/handlerMappers.ts b/src/dfs/generated/handlers/handlerMappers.ts new file mode 100644 index 000000000..7c72462b5 --- /dev/null +++ b/src/dfs/generated/handlers/handlerMappers.ts @@ -0,0 +1,679 @@ +import Operation from "../artifacts/operation"; + +// tslint:disable:one-line + +export interface IHandlerPath { + handler: string; + method: string; + arguments: string[]; +} + +const operationHandlerMapping: {[key: number]: IHandlerPath} = {}; + +operationHandlerMapping[Operation.Service_ListFileSystems] = { + arguments: [ + "options" + ], + handler: "serviceHandler", + method: "listFileSystems" +}; +operationHandlerMapping[Operation.Service_SetProperties] = { + arguments: [ + "storageServiceProperties", + "options" + ], + handler: "serviceHandler", + method: "setProperties" +}; +operationHandlerMapping[Operation.Service_GetProperties] = { + arguments: [ + "options" + ], + handler: "serviceHandler", + method: "getProperties" +}; +operationHandlerMapping[Operation.Service_GetStatistics] = { + arguments: [ + "options" + ], + handler: "serviceHandler", + method: "getStatistics" +}; +operationHandlerMapping[Operation.Service_ListContainersSegment] = { + arguments: [ + "options" + ], + handler: "serviceHandler", + method: "listContainersSegment" +}; +operationHandlerMapping[Operation.Service_GetUserDelegationKey] = { + arguments: [ + "keyInfo", + "options" + ], + handler: "serviceHandler", + method: "getUserDelegationKey" +}; +operationHandlerMapping[Operation.Service_GetAccountInfo] = { + arguments: [], + handler: "serviceHandler", + method: "getAccountInfo" +}; +operationHandlerMapping[Operation.Service_GetAccountInfoWithHead] = { + arguments: [], + handler: "serviceHandler", + method: "getAccountInfoWithHead" +}; +operationHandlerMapping[Operation.Service_SubmitBatch] = { + arguments: [ + "body", + "contentLength", + "multipartContentType", + "options" + ], + handler: "serviceHandler", + method: "submitBatch" +}; +operationHandlerMapping[Operation.Service_FilterBlobs] = { + arguments: [ + "options" + ], + handler: "serviceHandler", + method: "filterBlobs" +}; +operationHandlerMapping[Operation.FileSystem_Create] = { + arguments: [ + "options" + ], + handler: "fileSystemOperationsHandler", + method: "create" +}; +operationHandlerMapping[Operation.FileSystem_SetProperties] = { + arguments: [ + "options" + ], + handler: "fileSystemOperationsHandler", + method: "setProperties" +}; +operationHandlerMapping[Operation.FileSystem_GetProperties] = { + arguments: [ + "options" + ], + handler: "fileSystemOperationsHandler", + method: "getProperties" +}; +operationHandlerMapping[Operation.FileSystem_Delete] = { + arguments: [ + "options" + ], + handler: "fileSystemOperationsHandler", + method: "delete" +}; +operationHandlerMapping[Operation.FileSystem_ListPaths] = { + arguments: [ + "recursive", + "options" + ], + handler: "fileSystemOperationsHandler", + method: "listPaths" +}; +operationHandlerMapping[Operation.FileSystem_ListBlobFlatSegment] = { + arguments: [ + "options" + ], + handler: "fileSystemOperationsHandler", + method: "listBlobFlatSegment" +}; +operationHandlerMapping[Operation.FileSystem_ListBlobHierarchySegment] = { + arguments: [ + "delimiter", + "options" + ], + handler: "fileSystemOperationsHandler", + method: "listBlobHierarchySegment" +}; +operationHandlerMapping[Operation.Path_Create] = { + arguments: [ + "options" + ], + handler: "pathOperationsHandler", + method: "create" +}; +operationHandlerMapping[Operation.Path_Update] = { + arguments: [ + "action", + "mode", + "body", + "options" + ], + handler: "pathOperationsHandler", + method: "update" +}; +operationHandlerMapping[Operation.Path_Lease] = { + arguments: [ + "xMsLeaseAction", + "options" + ], + handler: "pathOperationsHandler", + method: "lease" +}; +operationHandlerMapping[Operation.Path_Read] = { + arguments: [ + "options" + ], + handler: "pathOperationsHandler", + method: "read" +}; +operationHandlerMapping[Operation.Path_GetProperties] = { + arguments: [ + "options" + ], + handler: "pathOperationsHandler", + method: "getProperties" +}; +operationHandlerMapping[Operation.Path_Delete] = { + arguments: [ + "options" + ], + handler: "pathOperationsHandler", + method: "delete" +}; +operationHandlerMapping[Operation.Path_SetAccessControl] = { + arguments: [ + "options" + ], + handler: "pathOperationsHandler", + method: "setAccessControl" +}; +operationHandlerMapping[Operation.Path_SetAccessControlRecursive] = { + arguments: [ + "mode", + "options" + ], + handler: "pathOperationsHandler", + method: "setAccessControlRecursive" +}; +operationHandlerMapping[Operation.Path_SetProperties] = { + arguments: [ + "options" + ], + handler: "pathOperationsHandler", + method: "setProperties" +}; +operationHandlerMapping[Operation.Path_FlushData] = { + arguments: [ + "options" + ], + handler: "pathOperationsHandler", + method: "flushData" +}; +operationHandlerMapping[Operation.Path_AppendData] = { + arguments: [ + "body", + "options" + ], + handler: "pathOperationsHandler", + method: "appendData" +}; +operationHandlerMapping[Operation.Path_SetExpiry] = { + arguments: [ + "expiryOptions", + "options" + ], + handler: "pathOperationsHandler", + method: "setExpiry" +}; +operationHandlerMapping[Operation.Path_Undelete] = { + arguments: [ + "options" + ], + handler: "pathOperationsHandler", + method: "undelete" +}; +operationHandlerMapping[Operation.Container_Create] = { + arguments: [ + "options" + ], + handler: "containerHandler", + method: "create" +}; +operationHandlerMapping[Operation.Container_GetProperties] = { + arguments: [ + "options" + ], + handler: "containerHandler", + method: "getProperties" +}; +operationHandlerMapping[Operation.Container_GetPropertiesWithHead] = { + arguments: [ + "options" + ], + handler: "containerHandler", + method: "getPropertiesWithHead" +}; +operationHandlerMapping[Operation.Container_Delete] = { + arguments: [ + "options" + ], + handler: "containerHandler", + method: "delete" +}; +operationHandlerMapping[Operation.Container_SetMetadata] = { + arguments: [ + "options" + ], + handler: "containerHandler", + method: "setMetadata" +}; +operationHandlerMapping[Operation.Container_GetAccessPolicy] = { + arguments: [ + "options" + ], + handler: "containerHandler", + method: "getAccessPolicy" +}; +operationHandlerMapping[Operation.Container_SetAccessPolicy] = { + arguments: [ + "options" + ], + handler: "containerHandler", + method: "setAccessPolicy" +}; +operationHandlerMapping[Operation.Container_Restore] = { + arguments: [ + "options" + ], + handler: "containerHandler", + method: "restore" +}; +operationHandlerMapping[Operation.Container_SubmitBatch] = { + arguments: [ + "body", + "contentLength", + "multipartContentType", + "options" + ], + handler: "containerHandler", + method: "submitBatch" +}; +operationHandlerMapping[Operation.Container_FilterBlobs] = { + arguments: [ + "options" + ], + handler: "containerHandler", + method: "filterBlobs" +}; +operationHandlerMapping[Operation.Container_AcquireLease] = { + arguments: [ + "options" + ], + handler: "containerHandler", + method: "acquireLease" +}; +operationHandlerMapping[Operation.Container_ReleaseLease] = { + arguments: [ + "leaseId", + "options" + ], + handler: "containerHandler", + method: "releaseLease" +}; +operationHandlerMapping[Operation.Container_RenewLease] = { + arguments: [ + "leaseId", + "options" + ], + handler: "containerHandler", + method: "renewLease" +}; +operationHandlerMapping[Operation.Container_BreakLease] = { + arguments: [ + "options" + ], + handler: "containerHandler", + method: "breakLease" +}; +operationHandlerMapping[Operation.Container_ChangeLease] = { + arguments: [ + "leaseId", + "proposedLeaseId", + "options" + ], + handler: "containerHandler", + method: "changeLease" +}; +operationHandlerMapping[Operation.Container_GetAccountInfo] = { + arguments: [], + handler: "containerHandler", + method: "getAccountInfo" +}; +operationHandlerMapping[Operation.Container_GetAccountInfoWithHead] = { + arguments: [], + handler: "containerHandler", + method: "getAccountInfoWithHead" +}; +operationHandlerMapping[Operation.PageBlob_Create] = { + arguments: [ + "contentLength", + "blobContentLength", + "options" + ], + handler: "pageBlobHandler", + method: "create" +}; +operationHandlerMapping[Operation.PageBlob_UploadPages] = { + arguments: [ + "body", + "contentLength", + "options" + ], + handler: "pageBlobHandler", + method: "uploadPages" +}; +operationHandlerMapping[Operation.PageBlob_ClearPages] = { + arguments: [ + "contentLength", + "options" + ], + handler: "pageBlobHandler", + method: "clearPages" +}; +operationHandlerMapping[Operation.PageBlob_UploadPagesFromURL] = { + arguments: [ + "sourceUrl", + "sourceRange", + "contentLength", + "range", + "options" + ], + handler: "pageBlobHandler", + method: "uploadPagesFromURL" +}; +operationHandlerMapping[Operation.PageBlob_GetPageRanges] = { + arguments: [ + "options" + ], + handler: "pageBlobHandler", + method: "getPageRanges" +}; +operationHandlerMapping[Operation.PageBlob_GetPageRangesDiff] = { + arguments: [ + "options" + ], + handler: "pageBlobHandler", + method: "getPageRangesDiff" +}; +operationHandlerMapping[Operation.PageBlob_Resize] = { + arguments: [ + "blobContentLength", + "options" + ], + handler: "pageBlobHandler", + method: "resize" +}; +operationHandlerMapping[Operation.PageBlob_UpdateSequenceNumber] = { + arguments: [ + "sequenceNumberAction", + "options" + ], + handler: "pageBlobHandler", + method: "updateSequenceNumber" +}; +operationHandlerMapping[Operation.PageBlob_CopyIncremental] = { + arguments: [ + "copySource", + "options" + ], + handler: "pageBlobHandler", + method: "copyIncremental" +}; +operationHandlerMapping[Operation.AppendBlob_Create] = { + arguments: [ + "contentLength", + "options" + ], + handler: "appendBlobHandler", + method: "create" +}; +operationHandlerMapping[Operation.AppendBlob_AppendBlock] = { + arguments: [ + "body", + "contentLength", + "options" + ], + handler: "appendBlobHandler", + method: "appendBlock" +}; +operationHandlerMapping[Operation.AppendBlob_AppendBlockFromUrl] = { + arguments: [ + "sourceUrl", + "contentLength", + "options" + ], + handler: "appendBlobHandler", + method: "appendBlockFromUrl" +}; +operationHandlerMapping[Operation.AppendBlob_Seal] = { + arguments: [ + "options" + ], + handler: "appendBlobHandler", + method: "seal" +}; +operationHandlerMapping[Operation.BlockBlob_Upload] = { + arguments: [ + "body", + "contentLength", + "options" + ], + handler: "blockBlobHandler", + method: "upload" +}; +operationHandlerMapping[Operation.BlockBlob_PutBlobFromUrl] = { + arguments: [ + "contentLength", + "copySource", + "options" + ], + handler: "blockBlobHandler", + method: "putBlobFromUrl" +}; +operationHandlerMapping[Operation.BlockBlob_StageBlock] = { + arguments: [ + "blockId", + "contentLength", + "body", + "options" + ], + handler: "blockBlobHandler", + method: "stageBlock" +}; +operationHandlerMapping[Operation.BlockBlob_StageBlockFromURL] = { + arguments: [ + "blockId", + "contentLength", + "sourceUrl", + "options" + ], + handler: "blockBlobHandler", + method: "stageBlockFromURL" +}; +operationHandlerMapping[Operation.BlockBlob_CommitBlockList] = { + arguments: [ + "blocks", + "options" + ], + handler: "blockBlobHandler", + method: "commitBlockList" +}; +operationHandlerMapping[Operation.BlockBlob_GetBlockList] = { + arguments: [ + "options" + ], + handler: "blockBlobHandler", + method: "getBlockList" +}; +operationHandlerMapping[Operation.Blob_Undelete] = { + arguments: [ + "options" + ], + handler: "blobHandler", + method: "undelete" +}; +operationHandlerMapping[Operation.Blob_SetExpiry] = { + arguments: [ + "expiryOptions", + "options" + ], + handler: "blobHandler", + method: "setExpiry" +}; +operationHandlerMapping[Operation.Blob_SetHTTPHeaders] = { + arguments: [ + "options" + ], + handler: "blobHandler", + method: "setHTTPHeaders" +}; +operationHandlerMapping[Operation.Blob_SetImmutabilityPolicy] = { + arguments: [ + "options" + ], + handler: "blobHandler", + method: "setImmutabilityPolicy" +}; +operationHandlerMapping[Operation.Blob_DeleteImmutabilityPolicy] = { + arguments: [ + "options" + ], + handler: "blobHandler", + method: "deleteImmutabilityPolicy" +}; +operationHandlerMapping[Operation.Blob_SetLegalHold] = { + arguments: [ + "legalHold", + "options" + ], + handler: "blobHandler", + method: "setLegalHold" +}; +operationHandlerMapping[Operation.Blob_SetMetadata] = { + arguments: [ + "options" + ], + handler: "blobHandler", + method: "setMetadata" +}; +operationHandlerMapping[Operation.Blob_AcquireLease] = { + arguments: [ + "options" + ], + handler: "blobHandler", + method: "acquireLease" +}; +operationHandlerMapping[Operation.Blob_ReleaseLease] = { + arguments: [ + "leaseId", + "options" + ], + handler: "blobHandler", + method: "releaseLease" +}; +operationHandlerMapping[Operation.Blob_RenewLease] = { + arguments: [ + "leaseId", + "options" + ], + handler: "blobHandler", + method: "renewLease" +}; +operationHandlerMapping[Operation.Blob_ChangeLease] = { + arguments: [ + "leaseId", + "proposedLeaseId", + "options" + ], + handler: "blobHandler", + method: "changeLease" +}; +operationHandlerMapping[Operation.Blob_BreakLease] = { + arguments: [ + "options" + ], + handler: "blobHandler", + method: "breakLease" +}; +operationHandlerMapping[Operation.Blob_CreateSnapshot] = { + arguments: [ + "options" + ], + handler: "blobHandler", + method: "createSnapshot" +}; +operationHandlerMapping[Operation.Blob_StartCopyFromURL] = { + arguments: [ + "copySource", + "options" + ], + handler: "blobHandler", + method: "startCopyFromURL" +}; +operationHandlerMapping[Operation.Blob_CopyFromURL] = { + arguments: [ + "copySource", + "options" + ], + handler: "blobHandler", + method: "copyFromURL" +}; +operationHandlerMapping[Operation.Blob_AbortCopyFromURL] = { + arguments: [ + "copyId", + "options" + ], + handler: "blobHandler", + method: "abortCopyFromURL" +}; +operationHandlerMapping[Operation.Blob_SetTier] = { + arguments: [ + "tier", + "options" + ], + handler: "blobHandler", + method: "setTier" +}; +operationHandlerMapping[Operation.Blob_GetAccountInfo] = { + arguments: [], + handler: "blobHandler", + method: "getAccountInfo" +}; +operationHandlerMapping[Operation.Blob_GetAccountInfoWithHead] = { + arguments: [], + handler: "blobHandler", + method: "getAccountInfoWithHead" +}; +operationHandlerMapping[Operation.Blob_Query] = { + arguments: [ + "options" + ], + handler: "blobHandler", + method: "query" +}; +operationHandlerMapping[Operation.Blob_GetTags] = { + arguments: [ + "options" + ], + handler: "blobHandler", + method: "getTags" +}; +operationHandlerMapping[Operation.Blob_SetTags] = { + arguments: [ + "options" + ], + handler: "blobHandler", + method: "setTags" +}; +function getHandlerByOperation(operation: Operation): IHandlerPath | undefined { + return operationHandlerMapping[operation]; +} +export default getHandlerByOperation; diff --git a/src/dfs/generated/middleware/HandlerMiddlewareFactory.ts b/src/dfs/generated/middleware/HandlerMiddlewareFactory.ts new file mode 100644 index 000000000..abd63dd5f --- /dev/null +++ b/src/dfs/generated/middleware/HandlerMiddlewareFactory.ts @@ -0,0 +1,90 @@ +import OperationMismatchError from '../../../blob/generated/errors/OperationMismatchError'; +import { NextFunction } from '../../../blob/generated/MiddlewareFactory'; +import ILogger from '../../../common/ILogger'; +import Operation from '../artifacts/operation'; +import Specifications from '../artifacts/specifications'; +import Context from '../../../blob/generated/Context'; +import getHandlerByOperation from '../handlers/handlerMappers'; +import IHandlers from '../handlers/IHandlers'; + +/** + * Auto generated. HandlerMiddlewareFactory will accept handlers and create handler middleware. + * + * @export + * @class HandlerMiddlewareFactory + */ +export default class HandlerMiddlewareFactory { + /** + * Creates an instance of HandlerMiddlewareFactory. + * Accept handlers and create handler middleware. + * + * @param {IHandlers} handlers Handlers implemented handler interfaces + * @param {ILogger} logger A valid logger + * @memberof HandlerMiddlewareFactory + */ + constructor( + private readonly handlers: IHandlers, + private readonly logger: ILogger + ) {} + + /** + * Creates a handler middleware from input handlers. + * + * @memberof HandlerMiddlewareFactory + */ + public createHandlerMiddleware(): ( + context: Context, + next: NextFunction + ) => void { + return (context: Context, next: NextFunction) => { + this.logger.info( + `HandlerMiddleware: DeserializedParameters=${JSON.stringify( + context.handlerParameters, + (key, value) => { + if (key === "body") { + return "ReadableStream"; + } + return value; + } + )}`, + context.contextId + ); + + if (context.context.dfsOperation === undefined) { + const handlerError = new OperationMismatchError(); + this.logger.error( + `HandlerMiddleware: ${handlerError.message}`, + context.contextId + ); + return next(handlerError); + } + + if (Specifications[context.context.dfsOperation] === undefined) { + this.logger.warn( + `HandlerMiddleware: cannot find handler for operation ${ + Operation[context.context.dfsOperation] + }` + ); + } + + // We assume handlerPath always exists for every generated operation in generated code + const handlerPath = getHandlerByOperation(context.context.dfsOperation)!; + + const args = []; + for (const arg of handlerPath.arguments) { + args.push(context.handlerParameters![arg]); + } + args.push(context); + + const handler = (this.handlers as any)[handlerPath.handler]; + const handlerMethod = handler[handlerPath.method] as () => Promise; + handlerMethod + .apply(handler, args as any) + .then((response: any) => { + context.handlerResponses = response; + }) + .then(next) + .catch(next); + }; + } +} diff --git a/src/dfs/generated/middleware/deserializer.middleware.ts b/src/dfs/generated/middleware/deserializer.middleware.ts new file mode 100644 index 000000000..35b84cb1c --- /dev/null +++ b/src/dfs/generated/middleware/deserializer.middleware.ts @@ -0,0 +1,59 @@ +import DeserializationError from '../../../blob/generated/errors/DeserializationError'; +import OperationMismatchError from '../../../blob/generated/errors/OperationMismatchError'; +import IRequest from '../../../blob/generated/IRequest'; +import { NextFunction } from '../../../blob/generated/MiddlewareFactory'; +import { deserialize } from '../../../blob/generated/utils/serializer'; +import ILogger from '../../../common/ILogger'; +import Operation from '../artifacts/operation'; +import Specifications from '../artifacts/specifications'; +import Context from '../../../blob/generated/Context'; + +/** + * Deserializer Middleware. Deserialize incoming HTTP request into models. + * + * @export + * @param {Context} context + * @param {IRequest} req An IRequest object + * @param {NextFunction} next An next callback or promise + * @param {ILogger} logger A valid logger + * @returns {void} + */ +export default function deserializerMiddleware( + context: Context, + req: IRequest, + next: NextFunction, + logger: ILogger +): void { + logger.verbose( + `DeserializerMiddleware: Start deserializing...`, + context.contextId + ); + + if (context.context.dfsOperation === undefined) { + const handlerError = new OperationMismatchError(); + logger.error( + `DeserializerMiddleware: ${handlerError.message}`, + context.contextId + ); + return next(handlerError); + } + + if (Specifications[context.context.dfsOperation] === undefined) { + logger.warn( + `DeserializerMiddleware: Cannot find deserializer for operation ${ + Operation[context.context.dfsOperation] + }` + ); + } + + deserialize(context, req, Specifications[context.context.dfsOperation], logger) + .then(parameters => { + context.handlerParameters = parameters; + }) + .then(next) + .catch(err => { + const deserializationError = new DeserializationError(err.message); + deserializationError.stack = err.stack; + next(deserializationError); + }); +} diff --git a/src/dfs/generated/middleware/dispatch.middleware.ts b/src/dfs/generated/middleware/dispatch.middleware.ts new file mode 100644 index 000000000..70e79f18b --- /dev/null +++ b/src/dfs/generated/middleware/dispatch.middleware.ts @@ -0,0 +1,191 @@ +import * as msRest from '@azure/ms-rest-js'; + +import Operation from '../artifacts/operation'; +import Specifications from '../artifacts/specifications'; +import Context from '../../../blob/generated/Context'; +import { operationDfsToBlob } from '../../utils/operationsMapper'; +import { NextFunction } from 'express'; +import IRequest from '../../../blob/generated/IRequest'; +import UnsupportedRequestError from '../../../blob/generated/errors/UnsupportedRequestError'; +import { isURITemplateMatch } from '../../../blob/generated/utils/utils'; +import ILogger from '../../../common/ILogger'; + +/** + * Dispatch Middleware will try to find out which operation of current HTTP request belongs to, + * by going through request specifications. Operation enum will be assigned to context object. + * Make sure dispatchMiddleware is triggered before other generated middleware. + * + * TODO: Add support for API priorities to deal with both matched APIs + * + * @export + * @param {Context} context Context object + * @param {IRequest} req An request object + * @param {NextFunction} next A callback + * @param {ILogger} logger A valid logger + * @returns {void} + */ +export default function dispatchMiddleware( + context: Context, + req: IRequest, + next: NextFunction, + logger: ILogger +): void { + logger.verbose( + `DispatchMiddleware: Dispatching request...`, + context.contextId + ); + + // Sometimes, more than one operations specifications are all valid against current request + // Such as a SetContainerMetadata request will fit both CreateContainer and SetContainerMetadata specifications + // We need to avoid this kind of situation when define swagger + // However, following code will try to find most suitable operation by selecting operation which + // have most required conditions met + let conditionsMet: number = -1; + + for (const key in Operation) { + if (Operation.hasOwnProperty(key)) { + const operation = parseInt(key, 10); + const res = isRequestAgainstOperation( + req, + Specifications[operation], + context.dispatchPattern + ); + if (res[0] && res[1] > conditionsMet) { + context.context.dfsOperation = operation; + context.operation = operationDfsToBlob(operation); + conditionsMet = res[1]; + } + } + } + + if (context.context.dfsOperation === undefined) { + const handlerError = new UnsupportedRequestError(); + logger.error( + `DispatchMiddleware: ${handlerError.message}`, + context.contextId + ); + return next(handlerError); + } + + logger.info( + `DispatchMiddleware: Operation=${Operation[context.context.dfsOperation]}`, + context.contextId + ); + + next(); +} + +/** + * Validation whether current request meets request operation specification. + * + * @param {IRequest} req + * @param {msRest.OperationSpec} spec + * @returns {[boolean, number]} Tuple includes validation result and number of met required conditions + */ +function isRequestAgainstOperation( + req: IRequest, + spec: msRest.OperationSpec, + dispatchPathPattern?: string +): [boolean, number] { + let metConditionsNum = 0; + if (req === undefined || spec === undefined) { + return [false, metConditionsNum]; + } + + const xHttpMethod = req.getHeader("X-HTTP-Method"); + let method = req.getMethod(); + if (xHttpMethod && xHttpMethod.length > 0) { + const value = xHttpMethod.trim(); + if ( + value === "GET" || + value === "MERGE" || + value === "PATCH" || + value === "DELETE" + ) { + method = value; + } + } + + // Validate HTTP method + if (method !== spec.httpMethod) { + return [false, metConditionsNum++]; + } + // Validate URL path + const path = spec.path + ? spec.path.startsWith("/") + ? spec.path + : `/${spec.path}` + : "/"; + if ( + !isURITemplateMatch( + // Use dispatch path with priority + dispatchPathPattern !== undefined ? dispatchPathPattern : req.getPath(), + path + ) + ) { + return [false, metConditionsNum++]; + } + + // Validate required queryParameters + for (const queryParameter of spec.queryParameters || []) { + if (queryParameter.mapper.required) { + const queryValue = req.getQuery( + queryParameter.mapper.serializedName || "" + ); + if (queryValue === undefined) { + return [false, metConditionsNum]; + } + + if ( + queryParameter.mapper.type.name === "Enum" && + queryParameter.mapper.type.allowedValues.findIndex((val) => { + return val === queryValue; + }) < 0 + ) { + return [false, metConditionsNum]; + } + + if ( + queryParameter.mapper.isConstant && + queryParameter.mapper.defaultValue !== queryValue + ) { + return [false, metConditionsNum]; + } + + metConditionsNum++; + } + } + + // Validate required header parameters + for (const headerParameter of spec.headerParameters || []) { + if (headerParameter.mapper.required) { + const headerValue = req.getHeader( + headerParameter.mapper.serializedName || "" + ); + if (headerValue === undefined) { + return [false, metConditionsNum]; + } + + if ( + headerParameter.mapper.type.name === "Enum" && + headerParameter.mapper.type.allowedValues.findIndex((val) => { + return val === headerValue; + }) < 0 + ) { + return [false, metConditionsNum]; + } + + if ( + headerParameter.mapper.isConstant && + `${headerParameter.mapper.defaultValue || ""}`.toLowerCase() !== + headerValue.toLowerCase() + ) { + return [false, metConditionsNum]; + } + + metConditionsNum++; + } + } + + return [true, metConditionsNum]; +} diff --git a/src/dfs/generated/middleware/error.middleware.ts b/src/dfs/generated/middleware/error.middleware.ts new file mode 100644 index 000000000..5885ff030 --- /dev/null +++ b/src/dfs/generated/middleware/error.middleware.ts @@ -0,0 +1,158 @@ +import StorageError from '../../../blob/errors/StorageError'; +import Context from '../../../blob/generated/Context'; +import IRequest from '../../../blob/generated/IRequest'; +import IResponse from '../../../blob/generated/IResponse'; +import { NextFunction } from '../../../blob/generated/MiddlewareFactory'; +import MiddlewareError from '../../../blob/generated/errors/MiddlewareError'; +import ILogger from '../../../common/ILogger'; +import DataLakeError from '../../errors/DataLakeError'; +import DataLakeErrorFactory from '../../errors/StorageErrorFactory'; + +/** + * ErrorMiddleware handles following 2 kinds of errors thrown from previous middleware or handlers: + * + * 1. MiddlewareError will be serialized. + * This includes most of expected errors, such as 4XX or some 5xx errors are MiddlewareError. + * + * 2. Other unexpected errors will be serialized to 500 Internal Server error directly. + * Every this kind of error should be carefully checked, and consider to handle it as a MiddlewareError. + * + * @export + * @param {Context} context + * @param {(MiddlewareError | Error)} err A MiddlewareError or Error object + * @param {Request} req An express compatible Request object + * @param {Response} res An express compatible Response object + * @param {NextFunction} next An express middleware next callback + * @param {ILogger} logger A valid logger + * @returns {void} + */ +export default function errorMiddleware( + context: Context, + err: MiddlewareError | Error, + req: IRequest, + res: IResponse, + next: NextFunction, + logger: ILogger +): void { + if (res.headersSent()) { + logger.warn( + `Error middleware received an error, but response.headersSent is true, pass error to next middleware`, + context.contextId + ); + return next(err); + } + + // Only handle ServerError, for other customized error types hand over to + // other error handlers. + err = convertToDataLakeError(err, context); + if (err instanceof MiddlewareError) { + logger.error( + `ErrorMiddleware: Received a MiddlewareError, fill error information to HTTP response`, + context.contextId + ); + + logger.error( + `ErrorMiddleware: ErrorName=${err.name} ErrorMessage=${ + err.message + } ErrorHTTPStatusCode=${err.statusCode} ErrorHTTPStatusMessage=${ + err.statusMessage + } ErrorHTTPHeaders=${JSON.stringify( + err.headers + )} ErrorHTTPBody=${JSON.stringify(err.body)} ErrorStack=${JSON.stringify( + err.stack + )}`, + context.contextId + ); + + logger.error( + `ErrorMiddleware: Set HTTP code: ${err.statusCode}`, + context.contextId + ); + + res.setStatusCode(err.statusCode); + if (err.statusMessage) { + logger.error( + `ErrorMiddleware: Set HTTP status message: ${err.statusMessage}`, + context.contextId + ); + res.setStatusMessage(err.statusMessage); + } + + if (err.headers) { + for (const key in err.headers) { + if (err.headers.hasOwnProperty(key)) { + const value = err.headers[key]; + if (value) { + logger.error( + `ErrorMiddleware: Set HTTP Header: ${key}=${value}`, + context.contextId + ); + res.setHeader(key, value); + } + } + } + } + + if (err.contentType && req.getMethod() !== "HEAD") { + logger.error( + `ErrorMiddleware: Set content type: ${err.contentType}`, + context.contextId + ); + res.setContentType(err.contentType); + } + + logger.error( + `ErrorMiddleware: Set HTTP body: ${JSON.stringify(err.body)}`, + context.contextId + ); + if (err.body && req.getMethod() !== "HEAD") { + res.getBodyStream().write(err.body); + } + } else if (err instanceof Error) { + logger.error( + `ErrorMiddleware: Received an error, fill error information to HTTP response`, + context.contextId + ); + logger.error( + `ErrorMiddleware: ErrorName=${err.name} ErrorMessage=${ + err.message + } ErrorStack=${JSON.stringify(err.stack)}`, + context.contextId + ); + logger.error(`ErrorMiddleware: Set HTTP code: ${500}`, context.contextId); + res.setStatusCode(500); + + // logger.error( + // `ErrorMiddleware: Set error message: ${err.message}`, + // context.contextID + // ); + // res.getBodyStream().write(err.message); + } else { + logger.warn( + `ErrorMiddleware: Received unhandled error object`, + context.contextId + ); + } + + next(); +} + +function convertToDataLakeError(e: Error, context: Context): Error { + if (!("storageErrorCode" in e)) return e; + const err: StorageError = e as StorageError; + + const [dataLakeErrorCode, dataLakeErrorMsg] = + DataLakeErrorFactory.blobErrorToDfsError( + err.storageErrorCode, + err.storageErrorMessage + ); + return new DataLakeError( + err.statusCode, + dataLakeErrorCode, + dataLakeErrorMsg, + err.storageErrorCode, + err.storageErrorMessage, + context, + err.storageAdditionalErrorMessages + ); +} diff --git a/src/dfs/generated/middleware/serializer.middleware.ts b/src/dfs/generated/middleware/serializer.middleware.ts new file mode 100644 index 000000000..247e6a66f --- /dev/null +++ b/src/dfs/generated/middleware/serializer.middleware.ts @@ -0,0 +1,57 @@ +import OperationMismatchError from '../../../blob/generated/errors/OperationMismatchError'; +import IResponse from '../../../blob/generated/IResponse'; +import { NextFunction } from '../../../blob/generated/MiddlewareFactory'; +import { serialize } from '../../../blob/generated/utils/serializer'; +import ILogger from '../../../common/ILogger'; +import Operation from '../artifacts/operation'; +import Specifications from '../artifacts/specifications'; +import Context from '../../../blob/generated/Context'; + +/** + * SerializerMiddleware will serialize models into HTTP responses. + * + * @export + * @param {Response} res + * @param {NextFunction} next + * @param {ILogger} logger + * @param {Context} context + */ +export default function serializerMiddleware( + context: Context, + res: IResponse, + next: NextFunction, + logger: ILogger +): void { + logger.verbose( + `SerializerMiddleware: Start serializing...`, + context.contextId + ); + + if (context.context.dfsOperation === undefined) { + const handlerError = new OperationMismatchError(); + logger.error( + `SerializerMiddleware: ${handlerError.message}`, + context.contextId + ); + return next(handlerError); + } + + if (Specifications[context.context.dfsOperation] === undefined) { + logger.warn( + `SerializerMiddleware: Cannot find serializer for operation ${ + Operation[context.context.dfsOperation] + }`, + context.contextId + ); + } + + serialize( + context, + res, + Specifications[context.context.dfsOperation], + context.handlerResponses, + logger + ) + .then(next) + .catch(next); +} diff --git a/src/dfs/handlers/BaseHandler.ts b/src/dfs/handlers/BaseHandler.ts new file mode 100644 index 000000000..03f30cb24 --- /dev/null +++ b/src/dfs/handlers/BaseHandler.ts @@ -0,0 +1,20 @@ +import ILogger from "../../common/ILogger"; +import IExtentStore from "../../common/persistence/IExtentStore"; +import IDataLakeMetadataStore from "../persistence/IDataLakeMetadataStore"; + +/** + * BaseHandler class should maintain a singleton to persistency layer, such as maintain a database connection pool. + * So every inherited classes instances can reuse the persistency layer connection. + * + * @export + * @class SimpleHandler + * @implements {IHandler} + */ +export default class BaseHandler { + constructor( + protected readonly metadataStore: IDataLakeMetadataStore, + protected readonly extentStore: IExtentStore, + protected readonly logger: ILogger, + protected readonly loose: boolean + ) {} +} diff --git a/src/dfs/handlers/FileSystemOperationsHandler.ts b/src/dfs/handlers/FileSystemOperationsHandler.ts new file mode 100644 index 000000000..e45c0f936 --- /dev/null +++ b/src/dfs/handlers/FileSystemOperationsHandler.ts @@ -0,0 +1,246 @@ +import { ContainerCreateResponse } from "../../blob/generated/artifacts/models"; +import BlobContainerHandler from "../../blob/handlers/ContainerHandler"; +import ILogger from "../../common/ILogger"; +import IExtentStore from "../../common/persistence/IExtentStore"; +import DataLakeContext from "../context/DataLakeContext"; +import * as Models from "../generated/artifacts/models"; +import Context from "../../blob/generated/Context"; +import IFileSystemOperationsHandler from "../generated/handlers/IFileSystemOperationsHandler"; +import IDataLakeMetaDataStore from "../persistence/IDataLakeMetadataStore"; +import { DATA_LAKE_API_VERSION } from "../utils/constants"; +import BaseHandler from "./BaseHandler"; + +/** + * FileSystemOperationsHandler handles Azure Storage DataLake Gen2 filesystem + * + * @export + * @class FileSystemOperationsHandler + * @extends {BaseHandler} + * @implements {IBlobHandler} + */ +export default class FileSystemOperationsHandler + extends BaseHandler + implements IFileSystemOperationsHandler +{ + constructor( + private readonly containerHandler: BlobContainerHandler, + metadataStore: IDataLakeMetaDataStore, + extentStore: IExtentStore, + logger: ILogger, + loose: boolean + ) { + super(metadataStore, extentStore, logger, loose); + } + + async create( + options: Models.FileSystemCreateOptionalParams, + context: Context + ): Promise { + const res: ContainerCreateResponse = await this.containerHandler.create( + options, + context + ); + + const response: Models.FileSystemCreateResponse = { + statusCode: 201, + clientRequestId: options.requestId, + eTag: res.eTag, + lastModified: res.lastModified, + date: context.startTime, + version: DATA_LAKE_API_VERSION, + namespaceEnabled: "true" + }; + + return response; + } + /** + * Set prodperties of a filesystem/container + * + * @param {Models.FileSystemSetPropertiesOptionalParams} options + * @param {Context} context + * @return {*} {Promise} + * @memberof FileSystemOperationsHandler + */ + async setProperties( + options: Models.FileSystemSetPropertiesOptionalParams, + context: Context + ): Promise { + const blobCtx = new DataLakeContext(context); + const accountName = blobCtx.account!; + const containerName = blobCtx.container!; + + const res = await this.metadataStore.setContainerProperties( + context, + accountName, + containerName, + options.properties === undefined ? "" : options.properties, + undefined, + options.modifiedAccessConditions + ); + + const response: Models.FileSystemSetPropertiesResponse = { + statusCode: 200, + date: blobCtx.startTime, + eTag: res.properties.etag, + lastModified: res.properties.lastModified, + requestId: options.requestId, + version: DATA_LAKE_API_VERSION + }; + + return response; + } + + async getProperties( + options: Models.FileSystemGetPropertiesOptionalParams, + context: Context + ): Promise { + const blobCtx = new DataLakeContext(context); + const accountName = blobCtx.account!; + const containerName = blobCtx.container!; + + const res = await this.metadataStore.getContainerProperties( + context, + accountName, + containerName + ); + + const response: Models.FileSystemGetPropertiesResponse = { + statusCode: 200, + date: blobCtx.startTime, + eTag: res.properties.etag, + lastModified: res.properties.lastModified, + properties: res.fileSystemProperties, + requestId: options.requestId, + version: DATA_LAKE_API_VERSION, + namespaceEnabled: "true" + }; + + return response; + } + + async delete( + options: Models.FileSystemDeleteMethodOptionalParams, + context: Context + ): Promise { + const blobCtx = new DataLakeContext(context); + const accountName = blobCtx.account!; + const containerName = blobCtx.container!; + + // TODO: Mark container as being deleted status, then (mark) delete all blobs async + // When above finishes, execute following delete container operation + // Because following delete container operation will only delete DB metadata for container and + // blobs under the container, but will not clean up blob data in disk + // The current design will directly remove the container and all the blobs belong to it. + await this.metadataStore.deleteContainer( + context, + accountName, + containerName, + options + ); + + const response: Models.FileSystemDeleteResponse = { + statusCode: 202, + requestId: context.contextId, + // clientRequestId: options.requestId, + date: context.startTime, + version: DATA_LAKE_API_VERSION + }; + + return response; + } + + async listPaths( + recursive: boolean, + options: Models.FileSystemListPathsOptionalParams, + context: Context + ): Promise { + const blobCtx = new DataLakeContext(context); + const accountName = blobCtx.account!; + const containerName = blobCtx.container!; + const directory = options.path || ""; + + const containerRes = await this.getProperties(options, context); + + const [paths, marker] = await this.metadataStore.listPaths( + context, + accountName, + containerName, + directory, + recursive, + options + ); + + const response: Models.FileSystemListPathsResponse = { + statusCode: 200, + date: containerRes.date, + eTag: containerRes.eTag, + lastModified: containerRes.lastModified, + requestId: containerRes.requestId, + version: DATA_LAKE_API_VERSION, + paths, + continuation: marker ? marker : undefined + }; + + return response; + } + + /** + * list blobs flat segments + * + * @param {Models.FileSystemListBlobFlatSegmentOptionalParams} options + * @param {Context} context + * @returns {Promise} + * @memberof ContainerHandler + */ + public async listBlobFlatSegment( + options: Models.FileSystemListBlobFlatSegmentOptionalParams, + context: Context + ): Promise { + return await this.containerHandler.listBlobFlatSegment( + options, + context + ); + } + + /** + * List blobs hierarchy. + * + * @param {string} delimiter + * @param {Models.ContainerListBlobHierarchySegmentOptionalParams} options + * @param {Context} context + * @returns {Promise} + * @memberof ContainerHandler + */ + async listBlobHierarchySegment( + delimiter: string, + options: Models.FileSystemListBlobHierarchySegmentOptionalParams, + context: Context + ): Promise { + return await this.containerHandler.listBlobHierarchySegment( + delimiter, + options, + context + ); + + // const response: Models.FileSystemListBlobHierarchySegmentResponse = { + // ...res, + // version: DATA_LAKE_API_VERSION, + // segment: { + // blobPrefixes: res.segment.blobPrefixes, + // blobItems: res.segment.blobItems.map((item) => { + // const newBlobItem: Models.BlobItemInternal = { + // ...item, + // properties: { + // ...item.properties, + // etag: removeQuotationFromListBlobEtag(item.properties.etag), + // accessTierInferred: + // item.properties.accessTierInferred === true ? true : undefined + // } + // }; + + // return newBlobItem; + // }) + // } + // }; + } +} diff --git a/src/dfs/handlers/PathOperationsHandler.ts b/src/dfs/handlers/PathOperationsHandler.ts new file mode 100644 index 000000000..2afa30adc --- /dev/null +++ b/src/dfs/handlers/PathOperationsHandler.ts @@ -0,0 +1,1358 @@ +import url from "url"; + +import BlobBlobHandler from "../../blob/handlers/BlobHandler"; +import { BlobModel } from "../../blob/persistence/IBlobMetadataStore"; +import ILogger from "../../common/ILogger"; +import IExtentStore from "../../common/persistence/IExtentStore"; +import { + getMD5FromStream, + getUniqueName, + newEtag +} from "../../common/utils/utils"; +import DataLakeContext from "../context/DataLakeContext"; +import NotImplementedError from "../errors/NotImplementedError"; +import StorageErrorFactory from "../errors/StorageErrorFactory"; +import * as Models from "../generated/artifacts/models"; +import Context from "../../blob/generated/Context"; +import IPathOperationsHandler from "../generated/handlers/IPathOperationsHandler"; +import IDataLakeMetaDataStore from "../persistence/IDataLakeMetadataStore"; +import { + permissionsStringToAclString, + toAcl, + toAclString, + toPermissions, + toPermissionsString +} from "../storagefiledatalake/transforms"; +import { + DATA_LAKE_API_VERSION, + DEFAULT_DIR_PERMISSIONS, + DEFAULT_FILE_PERMISSIONS, + DEFAULT_GROUP, + DEFAULT_OWNER, + DEFAULT_UMMASK, + HeaderConstants, + MAX_APPEND_BLOB_BLOCK_COUNT, + MAX_APPEND_BLOB_BLOCK_SIZE +} from "../utils/constants"; +import { removeSlash } from "../utils/utils"; +import BaseHandler from "./BaseHandler"; + +/** + * PathOperationsHandler handles Azure Storage DataLake Gen2 path + * + * @export + * @class PathOperationsHandler + * @extends {BaseHandler} + * @implements {IBlobHandler} + */ +export default class PathOperationsHandler + extends BaseHandler + implements IPathOperationsHandler +{ + constructor( + private readonly blobHandler: BlobBlobHandler, + metadataStore: IDataLakeMetaDataStore, + extentStore: IExtentStore, + logger: ILogger, + loose: boolean + ) { + super(metadataStore, extentStore, logger, loose); + } + + async create( + options: Models.PathCreateOptionalParams, + context: Context + ): Promise { + if (options.properties) { + const metadata: { [propertyName: string]: string } = + options.metadata || {}; + const metaDataValues = options.properties.split(","); + metaDataValues.forEach((pair) => { + const idx = pair.indexOf("="); + const name = pair.substring(0, idx); + const value = Buffer.from( + pair.substring(idx + 1), + "base64" + ).toString(); + + metadata[name] = value; + }); + + options.metadata = metadata; + } + + let response: Models.PathCreateResponse; + if (options.resource === "file") { + response = await this.createBlob(options, context); + } else if (options.resource === "directory") { + response = await this.createDirectory(options, context); + } else if (options.renameSource) { + response = await this.rename(options, context); + } else { + throw StorageErrorFactory.getInvalidQueryParameterValue( + context, + "resource", + options.resource, + "resource must be set to either 'file' or 'directory' or renameSource is set" + ); + } + + return response; + } + + async update( + action: Models.PathUpdateAction, + mode: Models.PathSetAccessControlRecursiveMode, + body: NodeJS.ReadableStream, + options: Models.PathUpdateOptionalParams, + context: Context + ): Promise { + switch (action) { + case Models.PathUpdateAction.Append: + return await this.appendData(body, options, context); + case Models.PathUpdateAction.Flush: + return await this.flushData(options, context); + case Models.PathUpdateAction.SetAccessControl: + return await this.setAccessControl(options, context); + case Models.PathUpdateAction.SetAccessControlRecursive: + return await this.setAccessControlRecursive(mode, options, context); + case Models.PathUpdateAction.SetProperties: + return await this.setProperties(options, context); + } + } + + async lease( + xMsLeaseAction: Models.PathLeaseAction, + options: Models.PathLeaseOptionalParams, + context: Context + ): Promise { + let response: Models.PathLeaseResponse; + switch (xMsLeaseAction) { + case Models.PathLeaseAction.Acquire: + await this.aquireLease(options, context); + response = { statusCode: 201, leaseId: options.proposedLeaseId }; + break; + case Models.PathLeaseAction.Break: + await this.breakLease(options, context); + response = { + statusCode: 202, + leaseTime: `${options.xMsLeaseBreakPeriod}` + }; + case Models.PathLeaseAction.Change: + await this.changeLease(options, context); + response = { statusCode: 200, leaseId: options.proposedLeaseId }; + break; + case Models.PathLeaseAction.Renew: + await this.renewLease(options, context); + response = { statusCode: 200, leaseId: options.proposedLeaseId }; + break; + case Models.PathLeaseAction.Release: + await this.releaseLease(options, context, false); + response = { statusCode: 200, leaseId: options.proposedLeaseId }; + break; + } + + const blobCtx = new DataLakeContext(context); + const account = blobCtx.account!; + const container = blobCtx.container!; + const blob = blobCtx.blob!; + const blobModel: BlobModel = await this.metadataStore.downloadBlob( + context, + account, + container, + blob, + "" + ); + response.date = context.startTime; + response.requestId = context.contextId; + response.eTag = blobModel?.properties.etag; + return response; + } + + async read( + options: Models.PathReadOptionalParams, + context: Context + ): Promise { + if (options.rangeGetContentCRC64 && options.rangeGetContentMD5) { + throw StorageErrorFactory.getInvalidInput( + context, + "rangeGetContentCRC64 and rangeGetContentCRC64 can't be both set at the same time" + ); + } + + context.context.blob = removeSlash(context.context.blob); + const res = await this.blobHandler.download( + options, + context + ); + + const response: Models.PathReadResponse = { + ...res, + resourceType: "file" + }; + + return response; + } + async setProperties( + options: Models.PathSetPropertiesOptionalParams, + context: Context + ): Promise { + const blobCtx = new DataLakeContext(context); + const account = blobCtx.account!; + const container = blobCtx.container!; + const blobName = removeSlash(blobCtx.blob!); + const model = await this.metadataStore.downloadBlob( + context, + account, + container, + blobName, + undefined, + options.leaseAccessConditions, + options.modifiedAccessConditions + ); + model.properties.cacheControl = options.pathHTTPHeaders?.cacheControl; + model.properties.contentDisposition = + options.pathHTTPHeaders?.contentDisposition; + model.properties.contentEncoding = + options.pathHTTPHeaders?.contentEncoding; + model.properties.contentLanguage = + options.pathHTTPHeaders?.contentLanguage; + model.properties.contentType = options.pathHTTPHeaders?.contentType; + model.properties.contentMD5 = options.pathHTTPHeaders?.contentMD5; + //FIXME: + // model.properties.properties = options.properties; + if (options.permissions) { + const permissions = toPermissions(options.permissions); + + if (permissions === undefined) { + throw StorageErrorFactory.getInvalidHeaderValue(context); + } + + model.permissions = toPermissionsString(permissions); + } + + this.metadataStore.createBlob( + context, + model, + options.leaseAccessConditions, + options.modifiedAccessConditions + ); + + const response: Models.PathSetPropertiesResponse = { + statusCode: 200, + cacheControl: options.pathHTTPHeaders?.cacheControl, + contentDisposition: options.pathHTTPHeaders?.contentDisposition, + contentEncoding: options.pathHTTPHeaders?.contentEncoding, + contentLanguage: options.pathHTTPHeaders?.contentLanguage, + contentType: options.pathHTTPHeaders?.contentType, + contentMD5: options.pathHTTPHeaders?.contentMD5, + properties: options.properties, + requestId: context.contextId, + clientRequestId: options.requestId, + date: context.startTime, + eTag: model.properties.etag, + lastModified: model.properties.lastModified, + contentLength: model.properties.contentLength, + version: DATA_LAKE_API_VERSION + }; + + return response; + } + + async getProperties( + options: Models.PathGetPropertiesOptionalParams, + context: Context + ): Promise { + context.context.blob = removeSlash(context.context.blob); + const res = await this.blobHandler.getProperties( + options, + context + ); + const blobCtx = new DataLakeContext(context); + const account = blobCtx.account!; + const container = blobCtx.container!; + const blobName = blobCtx.blob!; + const model = await this.metadataStore.downloadBlob( + context, + account, + container, + blobName, + options.snapshot, + options.leaseAccessConditions, + options.modifiedAccessConditions + ); + + const response: Models.PathGetPropertiesResponse = res; + response.metadata = model.metadata; + if (!model.isDirectory) { + response.resourceType = "file"; + response.blobCommittedBlockCount = + model.properties.blobType === Models.BlobType.AppendBlob + ? (model.committedBlocksInOrder || []).length + : undefined; + } else { + response.resourceType = "directory"; + if (response.metadata) { + response.metadata.hdi_isfolder = "true"; + } else { + response.metadata = { hdi_isfolder: "true" }; + } + } + + if ( + options.action === Models.PathGetPropertiesAction.GetAccessControl + ) { + response.owner = model.owner || DEFAULT_OWNER; + response.group = model.group || DEFAULT_GROUP; + response.permissions = model.permissions || DEFAULT_FILE_PERMISSIONS; + if (response.permissions || !model.acl) { + response.aCL = permissionsStringToAclString(response.permissions); + } else { + response.aCL = model.acl; + } + } + + return response; + } + + async delete( + options: Models.PathDeleteMethodOptionalParams, + context: Context + ): Promise { + const recursive = options.recursive || false; + const blobCtx = new DataLakeContext(context); + const accountName = blobCtx.account!; + const containerName = blobCtx.container!; + const blobName = removeSlash(blobCtx.blob!); + + await this.metadataStore.checkContainerExist( + context, + accountName, + containerName + ); + + const model = await this.metadataStore.getModel( + context, + accountName, + containerName, + blobName, + false, + options.leaseAccessConditions, + options.modifiedAccessConditions, + false + ); + + if (model === undefined) { + throw StorageErrorFactory.getBlobNotFound(context); + } + + if (!model.isDirectory) { + await this.metadataStore.deleteBlob( + context, + accountName, + containerName, + blobName, + options + ); + } else { + await this.metadataStore.deleteDirectory( + context, + accountName, + containerName, + blobName, + recursive, + options + ); + } + + //hack since Blob_Delete return 202 but Path_Delete return 200 + const accept = context.request?.getHeader("Accept"); + const statusCode = + accept !== undefined && accept.toLowerCase().includes("xml") + ? 202 + : 200; + const response: Models.PathDeleteResponse = { + statusCode, + requestId: context.contextId, + clientRequestId: options.requestId, + version: DATA_LAKE_API_VERSION, + date: context.startTime + }; + + return response; + } + + async setAccessControl( + options: Models.PathSetAccessControlOptionalParams, + context: Context + ): Promise { + const blobCtx = new DataLakeContext(context); + const account = blobCtx.account!; + const container = blobCtx.container!; + const blobName = removeSlash(blobCtx.blob!); + const model = await this.metadataStore.downloadBlob( + context, + account, + container, + blobName, + undefined, + options.leaseAccessConditions, + options.modifiedAccessConditions + ); + if (options.owner) model.owner = options.owner; + if (options.group) model.group = options.group; + + checkPermissionAclConflict(context, options); + + if (options.permissions) { + const permissions = toPermissions(options.permissions); + if (permissions === undefined) { + throw StorageErrorFactory.getInvalidHeaderValue(context); + } + model.permissions = options.permissions; + } + + if (options.acl) { + const acl = toAcl(options.acl); + if (acl === undefined) { + throw StorageErrorFactory.getInvalidHeaderValue(context); + } + + model.acl = options.acl; + } + + await this.metadataStore.createBlob( + context, + model, + options.leaseAccessConditions, + options.modifiedAccessConditions + ); + + const response: Models.PathSetAccessControlResponse = { + statusCode: 200, + requestId: context.contextId, + clientRequestId: options.requestId, + date: context.startTime, + eTag: model.properties.etag, + lastModified: model.properties.lastModified, + version: DATA_LAKE_API_VERSION + }; + + return response; + } + + async setAccessControlRecursive( + mode: Models.PathSetAccessControlRecursiveMode, + options: Models.PathSetAccessControlRecursiveOptionalParams, + context: Context + ): Promise { + const blobCtx = new DataLakeContext(context); + const account = blobCtx.account!; + const container = blobCtx.container!; + const blobName = removeSlash(blobCtx.blob!); + let directoriesSuccessful = 0; + let failedEntries: Models.AclFailedEntry[] = []; + let filesSuccessful = 0; + let failureCount = 0; + switch (mode) { + case Models.PathSetAccessControlRecursiveMode.Set: + const [paths] = await this.metadataStore.listPaths( + context, + account, + container, + blobName, + true, + options + ); + + paths.forEach(async (path) => { + try { + await this.setAccessControl(options, blobCtx); + path.isDirectory ? directoriesSuccessful++ : filesSuccessful++; + } catch (err) { + failedEntries.push({ + name: path.name, + type: err.errorCode, + errorMessage: err.errorMessage + }); + failureCount++; + } + }); + break; + case Models.PathSetAccessControlRecursiveMode.Modify: + case Models.PathSetAccessControlRecursiveMode.Remove: + throw new NotImplementedError(context); + } + + const response: Models.PathSetAccessControlRecursiveResponse = { + statusCode: 200, + clientRequestId: options.requestId, + requestId: context.contextId, + date: context.startTime, + version: DATA_LAKE_API_VERSION, + directoriesSuccessful, + failedEntries, + failureCount, + filesSuccessful + }; + return response; + } + + private uncommittedBlocks: Map = new Map< + string, + string[] + >(); + + async flushData( + options: Models.PathFlushDataOptionalParams, + context: Context + ): Promise { + await this.aquireLease(options, context); + await this.renewLease(options, context); + + const blobCtx = new DataLakeContext(context); + const account = blobCtx.account!; + const container = blobCtx.container!; + const blobName = removeSlash(blobCtx.blob!); + const model = await this.metadataStore.downloadBlob( + context, + account, + container, + blobName, + undefined, + options.leaseAccessConditions, + options.modifiedAccessConditions + ); + model.properties = { + ...model.properties, + cacheControl: + options.pathHTTPHeaders?.cacheControl || + model.properties.cacheControl, + contentDisposition: + options.pathHTTPHeaders?.contentDisposition || + model.properties.contentDisposition, + contentEncoding: + options.pathHTTPHeaders?.contentEncoding || + model.properties.contentEncoding, + contentLanguage: + options.pathHTTPHeaders?.contentLanguage || + model.properties.contentLanguage, + //TODO: need to be validated first + // contentMD5: options.pathHTTPHeaders?.contentMD5 || blobModel.properties.contentMD5, + contentType: + options.pathHTTPHeaders?.contentType || model.properties.contentType + }; + + this.metadataStore.createBlob( + context, + model, + options.leaseAccessConditions, + options.modifiedAccessConditions + ); + + const key = getKey(model); + let blocks: { blockName: string; blockCommitType: string }[]; + if (this.uncommittedBlocks.has(key)) { + blocks = this.uncommittedBlocks.get(key)!.map((blockName) => { + return { + blockName, + blockCommitType: "uncommitted" + }; + }); + + await this.metadataStore.flush( + context, + model, + blocks!, + options.leaseAccessConditions, + options.modifiedAccessConditions + ); + + this.uncommittedBlocks.delete(key); + } + + await this.releaseLease(options, context, false); + return { + statusCode: 200, + version: DATA_LAKE_API_VERSION, + clientRequestId: options.requestId, + requestId: context.contextId, + date: context.startTime, + contentLength: options.contentLength, + eTag: model.properties.etag, + lastModified: model.properties.lastModified, + isServerEncrypted: model.properties.serverEncrypted + }; + } + + async appendData( + body: NodeJS.ReadableStream, + options: Models.PathAppendDataOptionalParams, + context: Context + ): Promise { + await this.aquireLease(options, context); + await this.renewLease(options, context); + + const contentLength = options.contentLength!; + if (contentLength > MAX_APPEND_BLOB_BLOCK_SIZE) { + throw StorageErrorFactory.getRequestEntityTooLarge(context); + } + + if (contentLength === 0) { + throw StorageErrorFactory.getInvalidHeaderValue(context, { + HeaderName: HeaderConstants.CONTENT_LENGTH, + HeaderValue: "0" + }); + } + + const blobCtx = new DataLakeContext(context); + const account = blobCtx.account!; + const container = blobCtx.container!; + const blobName = removeSlash(blobCtx.blob!); + const blob = await this.metadataStore.downloadBlob( + context, + account, + container, + blobName, + undefined, + options.leaseAccessConditions, + options.modifiedAccessConditions + ); + + const committedBlockCount = (blob.committedBlocksInOrder || []).length; + if (committedBlockCount >= MAX_APPEND_BLOB_BLOCK_COUNT) { + throw StorageErrorFactory.getBlockCountExceedsLimit(context); + } + + // Persist content + const extent = await this.extentStore.appendExtent( + body, + context.contextId + ); + if (extent.count !== contentLength) { + throw StorageErrorFactory.getInvalidOperation( + context, + `The size of the request body ${extent.count} mismatches the content-length ${contentLength}.` + ); + } + + // MD5 + const contentMD5 = context.request!.getHeader( + HeaderConstants.CONTENT_MD5 + ); + let contentMD5Buffer; + let contentMD5String; + + if (contentMD5 !== undefined) { + contentMD5Buffer = + typeof contentMD5 === "string" + ? Buffer.from(contentMD5, "base64") + : contentMD5; + contentMD5String = + typeof contentMD5 === "string" + ? contentMD5 + : contentMD5Buffer.toString("base64"); + + const stream = await this.extentStore.readExtent( + extent, + context.contextId + ); + const calculatedContentMD5Buffer = await getMD5FromStream(stream); + const calculatedContentMD5String = Buffer.from( + calculatedContentMD5Buffer + ).toString("base64"); + + if (contentMD5String !== calculatedContentMD5String) { + throw StorageErrorFactory.getMd5Mismatch( + context, + contentMD5String, + calculatedContentMD5String + ); + } + } + + const key = getKey(blob); + const blockName = getUniqueName("block"); + await this.metadataStore.appendData( + context, + { + accountName: blob.accountName, + containerName: blob.containerName, + blobName: blob.name, + isCommitted: false, + name: blockName, + size: extent.count, + persistency: extent + }, + options.leaseAccessConditions + ); + + if (!this.uncommittedBlocks.has(key)) { + this.uncommittedBlocks.set(key, [blockName]); + } else { + this.uncommittedBlocks.get(key)?.push(blockName); + } + + const response: Models.PathAppendDataResponse = { + statusCode: 202, + eTag: blob.properties.etag, + contentMD5: contentMD5Buffer, + xMsContentCrc64: undefined, + clientRequestId: options.requestId, + version: DATA_LAKE_API_VERSION, + date: context.startTime, + requestId: context.contextId, + isServerEncrypted: true + }; + + if (options.flush) { + await this.flushData(options, context); + } else { + await this.releaseLease(options, context, true); + } + return response; + } + + async setExpiry( + expiryOptions: Models.PathExpiryOptions, + options: Models.PathSetExpiryOptionalParams, + context: Context + ): Promise { + const blobCtx = new DataLakeContext(context); + const accountName = blobCtx.account!; + const containerName = blobCtx.container!; + const blobName = blobCtx.blob!; + const date = context.startTime!; + + const blobModel = await this.metadataStore.downloadBlob( + context, + accountName, + containerName, + blobName, + "" + ); + + if ( + options.expiresOn === undefined && + expiryOptions !== Models.PathExpiryOptions.NeverExpire + ) { + throw StorageErrorFactory.getMissingRequestHeader(context); + } + let expiresOn: Date | undefined; + let timeToExpireInMs; + let startDate = date; + switch (expiryOptions) { + case Models.PathExpiryOptions.NeverExpire: + expiresOn = undefined; + break; + case Models.PathExpiryOptions.RelativeToCreation: + startDate = new Date(blobModel.properties.creationTime!); + case Models.PathExpiryOptions.RelativeToNow: + timeToExpireInMs = parseInt(options.expiresOn!); + if (isNaN(timeToExpireInMs)) { + throw StorageErrorFactory.getInvalidHeaderValue(context); + } + expiresOn = new Date(startDate.getTime() + timeToExpireInMs); + break; + case Models.PathExpiryOptions.Absolute: + expiresOn = new Date(options.expiresOn!); + break; + } + + blobModel.properties.expiresOn = expiresOn; + await this.metadataStore.createBlob(context, blobModel); + + const response: Models.PathSetExpiryResponse = { + statusCode: 200, + clientRequestId: options.requestId, + requestId: context.contextId, + date, + eTag: blobModel.properties.etag, + lastModified: blobModel.properties.lastModified + }; + + return response; + } + + undelete( + options: Models.PathUndeleteOptionalParams, + context: Context + ): Promise { + throw new NotImplementedError(context); + } + + private async createBlob( + options: Models.PathCreateOptionalParams, + context: Context + ): Promise { + const blobCtx = new DataLakeContext(context); + const accountName = blobCtx.account!; + const containerName = blobCtx.container!; + const blobName = blobCtx.blob!; + const date = context.startTime!; + const etag = newEtag(); + const contentLength = parseInt( + context.request!.getHeader("content-length") || "-1" + ); + + if (contentLength !== 0 && !this.loose) { + throw StorageErrorFactory.getInvalidOperation( + context, + "Content-Length must be 0 for Create Append Blob request." + ); + } + + checkPermissionAclConflict(context, options); + + const permissions = toPermissions( + options.permissions || DEFAULT_FILE_PERMISSIONS, + options.umask || DEFAULT_UMMASK + ); + + if (permissions === undefined) { + throw StorageErrorFactory.getInvalidHeaderValue(context); + } + + const acl = toAcl(options.acl); + + if (acl === undefined) { + throw StorageErrorFactory.getInvalidHeaderValue(context); + } + + let expiresOn: Date | undefined; + if (options.expiresOn) { + const timeToExpireInMs = parseInt(options.expiresOn); + if (isNaN(timeToExpireInMs)) { + expiresOn = new Date(options.expiresOn); + expiresOn.setMilliseconds(0); + } else { + expiresOn = new Date(date.getTime() + timeToExpireInMs); + } + } + + const contentType = + options.pathHTTPHeaders?.contentType || + context.request!.getHeader("content-type") || + "application/octet-stream"; + + const blob: BlobModel = { + deleted: false, + metadata: options.metadata, + accountName, + containerName, + name: blobName, + properties: { + creationTime: date, + lastModified: date, + etag, + contentLength: 0, + contentType, + expiresOn, + contentEncoding: options.pathHTTPHeaders?.contentEncoding, + contentLanguage: options.pathHTTPHeaders?.contentLanguage, + contentMD5: options.pathHTTPHeaders?.contentMD5, + contentDisposition: options.pathHTTPHeaders?.contentDisposition, + cacheControl: options.pathHTTPHeaders?.cacheControl, + accessTier: Models.AccessTier.Hot, + accessTierInferred: true, + blobType: Models.BlobType.AppendBlob, + leaseStatus: Models.LeaseStatusType.Unlocked, + leaseState: Models.LeaseStateType.Available, + serverEncrypted: true + }, + snapshot: "", + isCommitted: true, + isDirectory: false, + permissions: toPermissionsString(permissions), + acl: toAclString(acl), + owner: options.owner || DEFAULT_OWNER, + group: options.group || DEFAULT_GROUP, + committedBlocksInOrder: [] + }; + + this.setAdvancedOptions(blob, options, context); + + await this.metadataStore.createBlob( + context, + blob, + options.leaseAccessConditions, + options.modifiedAccessConditions + ); + + const response: Models.PathCreateResponse = { + statusCode: 201, + eTag: etag, + lastModified: blob.properties.lastModified, + // contentMD5: blob.properties.contentMD5, + requestId: context.contextId, + version: DATA_LAKE_API_VERSION, + date, + isServerEncrypted: true, + contentLength: 0 + // clientRequestId: options.requestId + }; + + const originalBlob = blobCtx.originalBlob!; + const idx = originalBlob.lastIndexOf("/"); + if (idx < 0) return response; + const dir = originalBlob.substring(0, idx); + options.modifiedAccessConditions = {}; + await this.createSpecificDirectory(options, context, dir, true); + + return response; + } + + private async createDirectory( + options: Models.PathCreateOptionalParams, + context: Context + ): Promise { + const blobCtx = new DataLakeContext(context); + const blob = blobCtx.blob!; + const recursive: boolean = + context.request?.getQuery("recursive") === "true" || true; + return await this.createSpecificDirectory( + options, + context, + blob, + recursive, + options.metadata + ); + } + private async createSpecificDirectory( + options: Models.PathCreateOptionalParams, + context: Context, + dir: string, + recursive: boolean, + metadata?: { [propertyName: string]: string } + ): Promise { + if (options.expiresOn) { + throw StorageErrorFactory.getInvalidInput( + context, + "Set Expiry is not supported for a directory" + ); + } + + const blobCtx = new DataLakeContext(context); + const account = blobCtx.account!; + const container = blobCtx.container!; + const date = context.startTime!; + const etag = newEtag(); + let leaseAccessConditions = options.leaseAccessConditions; + let modifiedAccessConditions = options.modifiedAccessConditions; + await this.metadataStore.checkContainerExist( + context, + account, + container + ); + + let curDir = dir.endsWith("/") ? dir.substring(0, dir.length - 1) : dir; + let parentDir; + do { + const curDirDecoded = decodeURIComponent(curDir); + const idx = curDir.lastIndexOf("/"); + parentDir = idx < 0 ? "" : curDir.substring(0, idx); + const dirModel = await this.metadataStore.getModel( + context, + account, + container, + curDirDecoded, + false, + leaseAccessConditions, + modifiedAccessConditions, + false + ); + + if ( + dirModel && + modifiedAccessConditions && + modifiedAccessConditions.ifNoneMatch === "*" + ) { + throw StorageErrorFactory.getBlobAlreadyExists(context); + } + + const permissions = toPermissions( + options.permissions || DEFAULT_DIR_PERMISSIONS, + options.umask || DEFAULT_UMMASK + ); + + if (permissions === undefined) { + throw StorageErrorFactory.getInvalidHeaderValue(context); + } + + const acl = toAcl(options.acl); + + if (acl === undefined) { + throw StorageErrorFactory.getInvalidHeaderValue(context); + } + + const newDirModel: BlobModel = { + deleted: false, + accountName: account, + containerName: container, + name: curDirDecoded, + properties: { + creationTime: date, + lastModified: date, + etag, + blobType: Models.BlobType.BlockBlob, + serverEncrypted: true, + accessTier: Models.AccessTier.Hot, + accessTierInferred: true, + accessTierChangeTime: date, + cacheControl: options.pathHTTPHeaders?.cacheControl, + contentEncoding: options.pathHTTPHeaders?.contentEncoding, + contentLanguage: options.pathHTTPHeaders?.contentLanguage, + contentDisposition: options.pathHTTPHeaders?.contentDisposition, + contentType: options.pathHTTPHeaders?.contentType + }, + isCommitted: true, + isDirectory: true, + snapshot: "", + metadata, + owner: options.owner || DEFAULT_OWNER, + group: options.group || DEFAULT_OWNER, + permissions: toPermissionsString(permissions), + acl: toAclString(acl) + }; + + this.setAdvancedOptions(newDirModel, options, context); + + await this.metadataStore.createBlob( + context, + newDirModel, + leaseAccessConditions, + modifiedAccessConditions + ); + + if (parentDir === "") break; + curDir = parentDir; + //Conditions are only valid for base directory + modifiedAccessConditions = {}; + leaseAccessConditions = {}; + } while (recursive); + + const response: Models.PathCreateResponse = { + statusCode: 201, + date, + eTag: etag, + lastModified: date, + requestId: options.requestId, + version: DATA_LAKE_API_VERSION, + contentLength: 0, + isServerEncrypted: true + }; + + return response; + } + + private async rename( + options: Models.PathCreateOptionalParams, + context: Context + ): Promise { + const blobCtx = new DataLakeContext(context); + const accountName = blobCtx.account!; + const targetContainer = blobCtx.container!; + const target = blobCtx.blob!; + + let renameSource = url.parse(options.renameSource!).pathname!; + if (renameSource.startsWith("/")) renameSource = renameSource.substring(1); + if (renameSource.startsWith(accountName + "/")) { + renameSource = renameSource.substring(accountName.length + 1); + } + const idx = renameSource.indexOf("/"); + const renameSourceContainer = renameSource.substring(0, idx); + renameSource = decodeURIComponent(renameSource.substring(idx + 1)); + + const model = await this.metadataStore.getModel( + context, + accountName, + renameSourceContainer, + renameSource, + true, + undefined, //we don't send options.leaseAccessConditions since they are for target not source + undefined, //we don't send options.modifiedAccessConditions since they are for target not source + false + ); + const renameFunc = model.isDirectory + ? this.metadataStore.renameDirectory + : this.metadataStore.renameBlob; + const newModel = await renameFunc.call( + this.metadataStore, + context, + accountName, + renameSourceContainer, + renameSource, + targetContainer, + target, + options + ); + + const response: Models.PathCreateResponse = { + statusCode: 201, + eTag: newModel.properties.etag, + lastModified: newModel.properties.lastModified, + requestId: context.contextId, + version: DATA_LAKE_API_VERSION, + contentLength: 0, // we don't sent a body so we must send contentLength to 0 + isServerEncrypted: newModel.properties.serverEncrypted, + date: context.startTime + }; + + return response; + } + + private setAdvancedOptions( + model: BlobModel, + options: Models.PathCreateOptionalParams, + context: Context + ): void { + if (options.proposedLeaseId) { + model.leaseId = options.proposedLeaseId; + model.properties.leaseStatus = Models.LeaseStatusType.Locked; + model.properties.leaseState = Models.LeaseStateType.Leased; + if (options.leaseDuration === -1) { + model.properties.leaseDuration = Models.LeaseDurationType.Infinite; + } else if (options.leaseDuration! < 15 || options.leaseDuration! > 60) { + throw StorageErrorFactory.getInvalidHeaderValue(context); + } else { + model.properties.leaseDuration = Models.LeaseDurationType.Fixed; + model.leaseDurationSeconds = options.leaseDuration; + model.leaseExpireTime = new Date( + context.startTime!.getTime() + options.leaseDuration! * 1000 + ); + } + } + } + + private async aquireLease( + options: + | Models.PathAppendDataOptionalParams + | Models.PathFlushDataOptionalParams + | Models.PathLeaseOptionalParams, + context: Context + ): Promise { + if ( + "leaseAction" in options && + options.leaseAction !== Models.LeaseAction.Acquire && + options.leaseAction !== Models.LeaseAction.AcquireRelease + ) + return; + + if (options.proposedLeaseId === undefined) { + throw StorageErrorFactory.getLeaseNotPresentWithLeaseOperation(context); + } + options.leaseAccessConditions! ||= {}; + + if (options.leaseAccessConditions.leaseId !== undefined) { + throw StorageErrorFactory.getInvalidHeaderValue(context); + } + + options.leaseAccessConditions.leaseId = options.proposedLeaseId; + + if (options.xMsLeaseDuration === undefined) { + throw StorageErrorFactory.getMissingRequestHeader(context); + } + + if (options.leaseAccessConditions.leaseId === undefined) { + throw StorageErrorFactory.getLeaseNotPresentWithLeaseOperation(context); + } + + const blobCtx = new DataLakeContext(context); + const account = blobCtx.account!; + const container = blobCtx.container!; + const blob = blobCtx.blob!; + const snapshot = blobCtx.request!.getQuery("snapshot"); + + if (snapshot !== undefined && snapshot !== "") { + throw StorageErrorFactory.getInvalidOperation( + context, + "A lease cannot be granted for a blob snapshot" + ); + } + + await this.metadataStore.acquireBlobLease( + context, + account, + container, + blob, + options.xMsLeaseDuration, + options.leaseAccessConditions.leaseId, + options + ); + } + + private async releaseLease( + options: + | Models.PathAppendDataOptionalParams + | Models.PathFlushDataOptionalParams + | Models.PathLeaseOptionalParams, + context: Context, + isAppend: boolean + ): Promise { + if ( + "leaseAction" in options && + options.leaseAction !== Models.LeaseAction.Release && + options.leaseAction !== Models.LeaseAction.AcquireRelease + ) + return; + + //https://learn.microsoft.com/en-us/rest/api/storageservices/datalakestoragegen2/path/update + //Starting with version 2020-08-04 ... 'Release' action is only supported in flush operation. + //but need it in case of skipApiVersion or loose + // if (isAppend && options.leaseAction === Models.LeaseAction.Release) { + // throw StorageErrorFactory.getInvalidHeaderValue(context); + // } + + options.leaseAccessConditions! ||= {}; + if (options.leaseAccessConditions.leaseId === undefined) { + throw StorageErrorFactory.getMissingRequestHeader(context); + } + + const blobCtx = new DataLakeContext(context); + const account = blobCtx.account!; + const container = blobCtx.container!; + const blob = blobCtx.blob!; + await this.metadataStore.releaseBlobLease( + context, + account, + container, + blob, + options.leaseAccessConditions.leaseId, + options + ); + } + + private async renewLease( + options: + | Models.PathAppendDataOptionalParams + | Models.PathFlushDataOptionalParams + | Models.PathLeaseOptionalParams, + context: Context + ): Promise { + if ( + "leaseAction" in options && + options.leaseAction !== Models.LeaseAction.Renew && + options.leaseAction !== Models.LeaseAction.AutoRenew + ) + return; + + options.leaseAccessConditions! ||= {}; + if (options.leaseAccessConditions.leaseId === undefined) { + throw StorageErrorFactory.getLeaseNotPresentWithLeaseOperation(context); + } + + const blobCtx = new DataLakeContext(context); + const account = blobCtx.account!; + const container = blobCtx.container!; + const blob = blobCtx.blob!; + const snapshot = blobCtx.request!.getQuery("snapshot"); + + if (snapshot !== undefined && snapshot !== "") { + throw StorageErrorFactory.getInvalidOperation( + context, + "A lease cannot be granted for a blob snapshot" + ); + } + + await this.metadataStore.renewBlobLease( + context, + account, + container, + blob, + options.leaseAccessConditions.leaseId, + options + ); + } + + private async breakLease( + options: Models.PathLeaseOptionalParams, + context: Context + ) { + options.leaseAccessConditions! ||= {}; + + if (options.xMsLeaseBreakPeriod === undefined) { + throw StorageErrorFactory.getMissingRequestHeader(context); + } + + if (options.leaseAccessConditions.leaseId === undefined) { + throw StorageErrorFactory.getLeaseNotPresentWithLeaseOperation(context); + } + + const blobCtx = new DataLakeContext(context); + const account = blobCtx.account!; + const container = blobCtx.container!; + const blob = blobCtx.blob!; + const snapshot = blobCtx.request!.getQuery("snapshot"); + + if (snapshot !== undefined && snapshot !== "") { + throw StorageErrorFactory.getInvalidOperation( + context, + "A lease cannot be granted for a blob snapshot" + ); + } + + await this.metadataStore.breakBlobLease( + context, + account, + container, + blob, + options.xMsLeaseBreakPeriod, + options + ); + } + + private async changeLease( + options: Models.PathLeaseOptionalParams, + context: Context + ) { + if (options.proposedLeaseId === undefined) { + throw StorageErrorFactory.getLeaseNotPresentWithLeaseOperation(context); + } + options.leaseAccessConditions! ||= {}; + if (options.xMsLeaseDuration === undefined) { + throw StorageErrorFactory.getMissingRequestHeader(context); + } + + if (options.leaseAccessConditions.leaseId === undefined) { + throw StorageErrorFactory.getLeaseNotPresentWithLeaseOperation(context); + } + + const blobCtx = new DataLakeContext(context); + const account = blobCtx.account!; + const container = blobCtx.container!; + const blob = blobCtx.blob!; + const snapshot = blobCtx.request!.getQuery("snapshot"); + + if (snapshot !== undefined && snapshot !== "") { + throw StorageErrorFactory.getInvalidOperation( + context, + "A lease cannot be granted for a blob snapshot" + ); + } + + await this.metadataStore.changeBlobLease( + context, + account, + container, + blob, + options.leaseAccessConditions.leaseId, + options.proposedLeaseId, + options + ); + } +} + +function checkPermissionAclConflict( + context: Context, + options: Models.PathSetAccessControlOptionalParams +) { + if (options.permissions && options.acl) { + throw StorageErrorFactory.getInvalidInput( + context, + "Permissions and Acl can't be both set at the same time" + ); + } +} +function getKey(model: BlobModel) { + return `${model.accountName}/${model.containerName}/${model.name}`; +} diff --git a/src/dfs/handlers/ServiceHandler.ts b/src/dfs/handlers/ServiceHandler.ts new file mode 100644 index 000000000..3bdee7b78 --- /dev/null +++ b/src/dfs/handlers/ServiceHandler.ts @@ -0,0 +1,61 @@ +import DataLakeContext from "../context/DataLakeContext"; +import * as Models from "../generated/artifacts/models"; +import Context from "../../blob/generated/Context"; +import IServiceHandler from "../generated/handlers/IServiceHandler"; +import { + DATA_LAKE_API_VERSION, + DEFAULT_LIST_CONTAINERS_MAX_RESULTS +} from "../utils/constants"; +import BlobServiceHandler from "../../blob/handlers/ServiceHandler"; + +/** + * ServiceHandler handles Azure Storage Blob service related requests. + * + * @export + * @class ServiceHandler + * @implements {IHandler} + */ +export default class ServiceHandler + extends BlobServiceHandler + implements IServiceHandler +{ + /** + * List filesystems aka containers. + * + * @param {Models.ServiceListFileSystemsOptionalParams} options + * @param {Context} context + * @returns {Promise} + * @memberof ServiceHandler + */ + async listFileSystems( + options: Models.ServiceListFileSystemsOptionalParams, + context: Context + ): Promise { + const blobCtx = new DataLakeContext(context); + const accountName = blobCtx.account!; + + options.maxResults = + options.maxResults || DEFAULT_LIST_CONTAINERS_MAX_RESULTS; + options.prefix = options.prefix || ""; + + const marker = options.continuation || ""; + + const [filesystems, continuation] = await this.metadataStore.listContainers( + context, + accountName, + options.prefix, + options.maxResults, + marker + ); + + const res: Models.ServiceListFileSystemsResponse = { + filesystems, + continuation, + statusCode: 200, + requestId: context.contextId, + version: DATA_LAKE_API_VERSION + }; + + return res; + } +} diff --git a/src/dfs/main.ts b/src/dfs/main.ts new file mode 100644 index 000000000..26d006ebb --- /dev/null +++ b/src/dfs/main.ts @@ -0,0 +1,56 @@ +#!/usr/bin/env node +import * as Logger from "../common/Logger"; +import DataLakeServer from "./DataLakeServer"; +import { DataLakeServerFactory } from "./DataLakeServerFactory"; +import SqlDataLakeServer from "./SqlDataLakeServer"; + +// tslint:disable:no-console + +function shutdown(server: DataLakeServer | SqlDataLakeServer) { + const beforeCloseMessage = `Azurite DataLake service is closing...`; + const afterCloseMessage = `Azurite DataLake service successfully closed`; + + console.log(beforeCloseMessage); + server.close().then(() => { + console.log(afterCloseMessage); + }); +} + +/** + * Entry for Azurite DataLake service. + */ +async function main() { + const blobServerFactory = new DataLakeServerFactory(); + const server = await blobServerFactory.createServer(); + const config = server.config; + + // We use logger singleton as global debugger logger to track detailed outputs cross layers + // Note that, debug log is different from access log which is only available in request handler layer to + // track every request. Access log is not singleton, and initialized in specific RequestHandlerFactory implementations + // Enable debug log by default before first release for debugging purpose + Logger.configLogger(config.enableDebugLog, config.debugLogFilePath); + + // Start server + console.log( + `Azurite DataLake service is starting on ${config.host}:${config.port}` + ); + await server.start(); + console.log( + `Azurite DataLake service successfully listens on ${server.getHttpServerAddress()}` + ); + + // Handle close event + process + .once("message", (msg) => { + if (msg === "shutdown") { + shutdown(server); + } + }) + .once("SIGINT", () => shutdown(server)) + .once("SIGTERM", () => shutdown(server)); +} + +main().catch((err) => { + console.error(`Exit due to unhandled error: ${err.message}`); + process.exit(1); +}); diff --git a/src/dfs/middlewares/AuthenticationMiddlewareFactory.ts b/src/dfs/middlewares/AuthenticationMiddlewareFactory.ts new file mode 100644 index 000000000..ad2515147 --- /dev/null +++ b/src/dfs/middlewares/AuthenticationMiddlewareFactory.ts @@ -0,0 +1,56 @@ +import { NextFunction, Request, RequestHandler, Response } from "express"; + +import StorageErrorFactory from "../errors/StorageErrorFactory"; +import { DEFAULT_CONTEXT_PATH } from "../../blob/utils/constants"; +import DataLakeContext from "../context/DataLakeContext"; +import IAuthenticator from "../authentication/IAuthenticator"; +import ILogger from "../../common/ILogger"; +import ExpressRequestAdapter from "../../blob/generated/ExpressRequestAdapter"; +import ExpressResponseAdapter from "../../blob/generated/ExpressResponseAdapter"; +import IRequest from "../../blob/generated/IRequest"; +import IResponse from "../../blob/generated/IResponse"; + +export default class AuthenticationMiddlewareFactory { + constructor(private readonly logger: ILogger) {} + + public createAuthenticationMiddleware( + authenticators: IAuthenticator[] + ): RequestHandler { + return (req: Request, res: Response, next: NextFunction) => { + const request = new ExpressRequestAdapter(req); + const response = new ExpressResponseAdapter(res); + const context = new DataLakeContext(res.locals, DEFAULT_CONTEXT_PATH); + this.authenticate(context, request, response, authenticators) + .then((pass) => { + // TODO: To support public access, we need to modify here to reject request later in handler + if (pass) { + next(); + } else { + next(StorageErrorFactory.getAuthorizationFailure(context)); + } + }) + .catch(next); + }; + } + + public async authenticate( + context: DataLakeContext, + req: IRequest, + res: IResponse, + authenticators: IAuthenticator[] + ): Promise { + this.logger.verbose( + `AuthenticationMiddlewareFactory:createAuthenticationMiddleware() Validating authentications.`, + context.contextId + ); + + let pass: boolean | undefined = false; + for (const authenticator of authenticators) { + pass = await authenticator.validate(req, context); + if (pass === true) { + return true; + } + } + return false; + } +} diff --git a/src/dfs/middlewares/PreflightMiddlewareFactory.ts b/src/dfs/middlewares/PreflightMiddlewareFactory.ts new file mode 100644 index 000000000..64c4cbd13 --- /dev/null +++ b/src/dfs/middlewares/PreflightMiddlewareFactory.ts @@ -0,0 +1,458 @@ +import * as msRest from "@azure/ms-rest-js"; +import { + ErrorRequestHandler, + NextFunction, + Request, + RequestHandler, + Response +} from "express"; + +import glob from "glob-to-regexp"; +import ILogger from "../../common/ILogger"; +import DataLakeContext from "../context/DataLakeContext"; +import StorageErrorFactory from "../errors/StorageErrorFactory"; +import * as Mappers from "../generated/artifacts/mappers"; +import Specifications from "../generated/artifacts/specifications"; +import IDataLakeMetadataStore from "../persistence/IDataLakeMetadataStore"; +import { HeaderConstants, MethodConstants } from "../utils/constants"; +import { DEFAULT_CONTEXT_PATH } from "../../blob/utils/constants"; +import MiddlewareError from "../../blob/generated/errors/MiddlewareError"; + +export default class PreflightMiddlewareFactory { + constructor(private readonly logger: ILogger) {} + + public createOptionsHandlerMiddleware( + metadataStore: IDataLakeMetadataStore + ): ErrorRequestHandler { + return ( + err: MiddlewareError | Error, + req: Request, + res: Response, + next: NextFunction + ) => { + if (req.method.toUpperCase() === MethodConstants.OPTIONS) { + const context = new DataLakeContext(res.locals, DEFAULT_CONTEXT_PATH); + + const requestId = context.contextId; + const account = context.account!; + + this.logger.info( + `PreflightMiddlewareFactory.createOptionsHandlerMiddleware(): OPTIONS request.`, + requestId + ); + + const origin = req.header(HeaderConstants.ORIGIN); + if (origin === undefined || typeof origin !== "string") { + return next( + StorageErrorFactory.getInvalidCorsHeaderValue(context, { + MessageDetails: `Invalid required CORS header Origin ${JSON.stringify( + origin + )}` + }) + ); + } + + const requestMethod = req.header( + HeaderConstants.ACCESS_CONTROL_REQUEST_METHOD + ); + if (requestMethod === undefined || typeof requestMethod !== "string") { + return next( + StorageErrorFactory.getInvalidCorsHeaderValue(context, { + MessageDetails: `Invalid required CORS header Access-Control-Request-Method ${JSON.stringify( + requestMethod + )}` + }) + ); + } + + const requestHeaders = req.headers[ + HeaderConstants.ACCESS_CONTROL_REQUEST_HEADERS + ] as string; + + metadataStore + .getServiceProperties(context, account) + .then((properties) => { + if (properties === undefined || properties.cors === undefined) { + return next( + StorageErrorFactory.corsPreflightFailure(context, { + MessageDetails: "No CORS rules matches this request" + }) + ); + } + + const corsSet = properties.cors; + for (const cors of corsSet) { + if ( + !this.checkOrigin(origin, cors.allowedOrigins) || + !this.checkMethod(requestMethod, cors.allowedMethods) + ) { + continue; + } + if ( + requestHeaders !== undefined && + !this.checkHeaders(requestHeaders, cors.allowedHeaders || "") + ) { + continue; + } + + res.setHeader( + HeaderConstants.ACCESS_CONTROL_ALLOW_ORIGIN, + origin + ); + res.setHeader( + HeaderConstants.ACCESS_CONTROL_ALLOW_METHODS, + requestMethod + ); + if (requestHeaders !== undefined) { + res.setHeader( + HeaderConstants.ACCESS_CONTROL_ALLOW_HEADERS, + requestHeaders + ); + } + res.setHeader( + HeaderConstants.ACCESS_CONTROL_MAX_AGE, + cors.maxAgeInSeconds + ); + res.setHeader( + HeaderConstants.ACCESS_CONTROL_ALLOW_CREDENTIALS, + "true" + ); + + return next(); + } + return next( + StorageErrorFactory.corsPreflightFailure(context, { + MessageDetails: "No CORS rules matches this request" + }) + ); + }) + .catch(next); + } else { + next(err); + } + }; + } + + public createCorsRequestMiddleware( + metadataStore: IDataLakeMetadataStore, + blockErrorRequest: boolean = false + ): ErrorRequestHandler | RequestHandler { + const internalMethod = ( + err: MiddlewareError | Error | undefined, + req: Request, + res: Response, + next: NextFunction + ) => { + if (req.method.toUpperCase() === MethodConstants.OPTIONS) { + return next(err); + } + + const context = new DataLakeContext(res.locals, DEFAULT_CONTEXT_PATH); + + const account = context.account!; + + const origin = req.headers[HeaderConstants.ORIGIN] as string | undefined; + if (origin === undefined) { + return next(err); + } + + const method = req.method; + if (method === undefined || typeof method !== "string") { + return next(err); + } + + metadataStore + .getServiceProperties(context, account) + .then((properties) => { + if (properties === undefined || properties.cors === undefined) { + return next(err); + } + const corsSet = properties.cors; + const resHeaders = this.getResponseHeaders( + res, + err instanceof MiddlewareError ? err : undefined + ); + + // Here we will match CORS settings in order and select first matched CORS + for (const cors of corsSet) { + if ( + this.checkOrigin(origin, cors.allowedOrigins) && + this.checkMethod(method, cors.allowedMethods) + ) { + const exposedHeaders = this.getExposedHeaders( + resHeaders, + cors.exposedHeaders || "" + ); + + res.setHeader( + HeaderConstants.ACCESS_CONTROL_EXPOSE_HEADERS, + exposedHeaders + ); + + res.setHeader( + HeaderConstants.ACCESS_CONTROL_ALLOW_ORIGIN, + cors.allowedOrigins === "*" ? "*" : origin! // origin is not undefined as checked in checkOrigin() + ); + + if (cors.allowedOrigins !== "*") { + res.setHeader(HeaderConstants.VARY, "Origin"); + res.setHeader( + HeaderConstants.ACCESS_CONTROL_ALLOW_CREDENTIALS, + "true" + ); + } + + return next(err); + } + } + if (corsSet.length > 0) { + res.setHeader(HeaderConstants.VARY, "Origin"); + } + return next(err); + }) + .catch(next); + }; + + if (blockErrorRequest) { + return internalMethod; + } else { + return (req: Request, res: Response, next: NextFunction) => { + internalMethod(undefined, req, res, next); + }; + } + } + + private checkOrigin( + origin: string | undefined, + allowedOrigin: string + ): boolean { + if (allowedOrigin === "*") { + return true; + } + + if (origin === undefined) { + return false; + } + + const allowedOriginArray = allowedOrigin.split(","); + for (const corsOrigin of allowedOriginArray) { + if (corsOrigin.includes("*")) { + return glob(corsOrigin.trim().toLowerCase()).test( + origin.trim().toLowerCase() + ); + } + + if (origin.trim().toLowerCase() === corsOrigin.trim().toLowerCase()) { + return true; + } + } + return false; + } + + private checkMethod(method: string, allowedMethod: string): boolean { + const allowedMethodArray = allowedMethod.split(","); + for (const corsMethod of allowedMethodArray) { + if (method.trim().toLowerCase() === corsMethod.trim().toLowerCase()) { + return true; + } + } + return false; + } + + private checkHeaders(headers: string, allowedHeaders: string): boolean { + const headersArray = headers.split(","); + const allowedHeadersArray = allowedHeaders.split(","); + for (const header of headersArray) { + let flag = false; + const trimmedHeader = header.trim().toLowerCase(); + + for (const allowedHeader of allowedHeadersArray) { + // TODO: Should remove the wrapping blank when set CORS through set properties for service. + const trimmedAllowedHeader = allowedHeader.trim().toLowerCase(); + if ( + trimmedHeader === trimmedAllowedHeader || + (trimmedAllowedHeader[trimmedAllowedHeader.length - 1] === "*" && + trimmedHeader.startsWith( + trimmedAllowedHeader.substr(0, trimmedAllowedHeader.length - 1) + )) + ) { + flag = true; + break; + } + } + + if (flag === false) { + return false; + } + } + + return true; + } + + private getResponseHeaders(res: Response, err?: MiddlewareError): string[] { + const responseHeaderSet = []; + + const context = new DataLakeContext(res.locals, DEFAULT_CONTEXT_PATH); + const handlerResponse = context.handlerResponses; + + if (handlerResponse && context.context.dfsOperation) { + const statusCodeInResponse: number = handlerResponse.statusCode; + const spec = Specifications[context.context.dfsOperation]; + const responseSpec = spec.responses[statusCodeInResponse]; + if (!responseSpec) { + throw new TypeError( + `Request specification doesn't include provided response status code` + ); + } + + // Serialize headers + const headerSerializer = new msRest.Serializer(Mappers); + const headersMapper = responseSpec.headersMapper; + + if (headersMapper && headersMapper.type.name === "Composite") { + const mappersForAllHeaders = headersMapper.type.modelProperties || {}; + + // Handle headerMapper one by one + for (const key in mappersForAllHeaders) { + if (mappersForAllHeaders.hasOwnProperty(key)) { + const headerMapper = mappersForAllHeaders[key]; + const headerName = headerMapper.serializedName; + const headerValueOriginal = handlerResponse[key]; + const headerValueSerialized = headerSerializer.serialize( + headerMapper, + headerValueOriginal + ); + + // Handle collection of headers starting with same prefix, such as x-ms-meta prefix + const headerCollectionPrefix = ( + headerMapper as msRest.DictionaryMapper + ).headerCollectionPrefix; + if ( + headerCollectionPrefix !== undefined && + headerValueOriginal !== undefined + ) { + for (const collectionHeaderPartialName in headerValueSerialized) { + if ( + headerValueSerialized.hasOwnProperty( + collectionHeaderPartialName + ) + ) { + const collectionHeaderValueSerialized = + headerValueSerialized[collectionHeaderPartialName]; + const collectionHeaderName = `${headerCollectionPrefix}${collectionHeaderPartialName}`; + if ( + collectionHeaderName && + collectionHeaderValueSerialized !== undefined + ) { + responseHeaderSet.push(collectionHeaderName); + } + } + } + } else { + if (headerName && headerValueSerialized !== undefined) { + responseHeaderSet.push(headerName); + } + } + } + } + } + + if ( + spec.isXML && + responseSpec.bodyMapper && + responseSpec.bodyMapper.type.name !== "Stream" + ) { + responseHeaderSet.push("content-type"); + responseHeaderSet.push("content-length"); + } else if ( + handlerResponse.body && + responseSpec.bodyMapper && + responseSpec.bodyMapper.type.name === "Stream" + ) { + responseHeaderSet.push("content-length"); + } + } + + const headers = res.getHeaders(); + for (const header in headers) { + if (typeof header === "string") { + responseHeaderSet.push(header); + } + } + + if (err) { + for (const key in err.headers) { + if (err.headers.hasOwnProperty(key)) { + responseHeaderSet.push(key); + } + } + } + + // TODO: Should extract the header by some policy. + // or apply a referred list indicates the related headers. + responseHeaderSet.push("Date"); + responseHeaderSet.push("Connection"); + responseHeaderSet.push("Transfer-Encoding"); + + return responseHeaderSet; + } + + private getExposedHeaders( + responseHeaders: any, + exposedHeaders: string + ): string { + const exposedHeaderRules = exposedHeaders.split(","); + const prefixRules = []; + const simpleHeaders = []; + for (let i = 0; i < exposedHeaderRules.length; i++) { + exposedHeaderRules[i] = exposedHeaderRules[i].trim(); + if (exposedHeaderRules[i].endsWith("*")) { + prefixRules.push( + exposedHeaderRules[i] + .substr(0, exposedHeaderRules[i].length - 1) + .toLowerCase() + ); + } else { + simpleHeaders.push(exposedHeaderRules[i]); + } + } + + const resExposedHeaders: string[] = []; + for (const header of responseHeaders) { + let isMatch = false; + for (const rule of prefixRules) { + if (header.toLowerCase().startsWith(rule)) { + isMatch = true; + break; + } + } + if (!isMatch) { + for (const simpleHeader of simpleHeaders) { + if (header.toLowerCase() === simpleHeader.toLowerCase()) { + isMatch = true; + break; + } + } + } + + if (isMatch) { + resExposedHeaders.push(header); + } + } + + for (const simpleHeader of simpleHeaders) { + let isMatch = false; + for (const header of resExposedHeaders) { + if (simpleHeader.toLowerCase() === header.toLowerCase()) { + isMatch = true; + break; + } + } + if (!isMatch) { + resExposedHeaders.push(simpleHeader); + } + } + + return resExposedHeaders.join(","); + } +} diff --git a/src/dfs/middlewares/StrictModelMiddlewareFactory.ts b/src/dfs/middlewares/StrictModelMiddlewareFactory.ts new file mode 100644 index 000000000..f15e3cb12 --- /dev/null +++ b/src/dfs/middlewares/StrictModelMiddlewareFactory.ts @@ -0,0 +1,72 @@ +import { NextFunction, Request, RequestHandler, Response } from "express"; + +import ILogger from "../../common/ILogger"; +import StrictModelNotSupportedError from "../errors/StrictModelNotSupportedError"; +import Context from "../../blob/generated/Context"; +import { HeaderConstants } from "../utils/constants"; +import { DEFAULT_CONTEXT_PATH } from "../../blob/utils/constants"; +import DataLakeContext from "../context/DataLakeContext"; +import IRequest from "../../blob/generated/IRequest"; +import ExpressRequestAdapter from "../../blob/generated/ExpressRequestAdapter"; + +export type StrictModelRequestValidator = ( + req: IRequest, + context: Context, + logger: ILogger +) => Promise; + +export const UnsupportedHeadersBlocker: StrictModelRequestValidator = async ( + req: IRequest, + context: Context, + logger: ILogger +): Promise => { + const UnsupportedHeaderKeys = [ + HeaderConstants.X_MS_CONTENT_CRC64, + HeaderConstants.X_MS_RANGE_GET_CONTENT_CRC64, + HeaderConstants.X_MS_ENCRYPTION_KEY, + HeaderConstants.X_MS_ENCRYPTION_KEY_SHA256, + HeaderConstants.X_MS_ENCRYPTION_ALGORITHM + ]; + + for (const headerKey of UnsupportedHeaderKeys) { + const value = req.getHeader(headerKey); + if (typeof value === "string") { + throw new StrictModelNotSupportedError(headerKey, context); + } + } +}; + +export const UnsupportedParametersBlocker: StrictModelRequestValidator = async ( + req: IRequest, + context: Context, + logger: ILogger +): Promise => { + const UnsupportedParameterKeys: string[] = []; + + for (const parameterKey of UnsupportedParameterKeys) { + const value = req.getQuery(parameterKey); + if (typeof value === "string") { + throw new StrictModelNotSupportedError(parameterKey, context); + } + } +}; + +export default class StrictModelMiddlewareFactory { + constructor( + private readonly logger: ILogger, + private readonly validators: StrictModelRequestValidator[] + ) {} + + public createStrictModelMiddleware(): RequestHandler { + return (req: Request, res: Response, next: NextFunction) => { + this.validate(req, res).then(next).catch(next); + }; + } + + private async validate(req: Request, res: Response): Promise { + const context = new DataLakeContext(res.locals, DEFAULT_CONTEXT_PATH); + for (const validator of this.validators) { + await validator(new ExpressRequestAdapter(req), context, this.logger); + } + } +} diff --git a/src/dfs/middlewares/blobStorageContext.middleware.ts b/src/dfs/middlewares/blobStorageContext.middleware.ts new file mode 100644 index 000000000..b984a0371 --- /dev/null +++ b/src/dfs/middlewares/blobStorageContext.middleware.ts @@ -0,0 +1,282 @@ +import { NextFunction, Request, RequestHandler, Response } from "express"; +import uuid from "uuid/v4"; + +import logger from "../../common/Logger"; +import { IP_REGEX } from "../../common/utils/constants"; +import { NO_ACCOUNT_HOST_NAMES } from "../../common/utils/constants"; +import DataLakeContext from "../context/DataLakeContext"; +import StorageErrorFactory from "../errors/StorageErrorFactory"; +import { + HeaderConstants, + SECONDARY_SUFFIX, + ValidAPIVersions, + VERSION +} from "../utils/constants"; +import { checkApiVersion, validateContainerName } from "../utils/utils"; +import { DEFAULT_CONTEXT_PATH } from "../../blob/utils/constants"; +import IResponse from "../../blob/generated/IResponse"; +import IRequest from "../../blob/generated/IRequest"; + +export default function createStorageBlobContextMiddleware( + skipApiVersionCheck?: boolean, + disableProductStyleUrl?: boolean, + loose?: boolean +): RequestHandler { + return (req: Request, res: Response, next: NextFunction) => { + return blobStorageContextMiddleware( + req, + res, + next, + skipApiVersionCheck, + disableProductStyleUrl, + loose + ); + }; +} + +/** + * A middleware extract related blob service context. + * + * @export + * @param {Request} req An express compatible Request object + * @param {Response} res An express compatible Response object + * @param {NextFunction} next An express middleware next callback + */ +export function internnalBlobStorageContextMiddleware( + blobContext: DataLakeContext, + req: IRequest, + res: IResponse, + reqHost: string, + reqPath: string, + next: NextFunction, + skipApiVersionCheck?: boolean, + disableProductStyleUrl?: boolean, + loose?: boolean +): void { + // Set server header in every Azurite response + res.setHeader(HeaderConstants.SERVER, `Azurite-DataLake/${VERSION}`); + const requestID = uuid(); + + if (!skipApiVersionCheck) { + const apiVersion = req.getHeader(HeaderConstants.X_MS_VERSION); + if (apiVersion !== undefined) { + checkApiVersion(apiVersion, ValidAPIVersions, blobContext); + } + } + + blobContext.startTime = new Date(); + blobContext.disableProductStyleUrl = disableProductStyleUrl; + blobContext.loose = loose; + + blobContext.xMsRequestID = requestID; + + logger.info( + `BlobStorageContextMiddleware: RequestMethod=${req.getMethod()} RequestURL=${req.getUrl()} RequestHeaders:${JSON.stringify( + req.getHeaders() + )} ClientIP=${req.getEndpoint()} Protocol=${req.getProtocol()} HTTPVersion=version`, + requestID + ); + + const [account, container, blob, originalBlob, isSecondary] = + extractStoragePartsFromPath(reqHost, reqPath, disableProductStyleUrl); + + blobContext.account = account; + blobContext.container = container; + blobContext.blob = blob; + blobContext.originalBlob = originalBlob; + blobContext.isSecondary = isSecondary; + + // Emulator's URL pattern is like http://hostname[:port]/account/container + // (or, alternatively, http[s]://account.localhost[:port]/container) + // Create a router to exclude account name from req.path, as url path in swagger doesn't include account + // Exclude account name from req.path for dispatchMiddleware + blobContext.dispatchPattern = container + ? blob + ? `/container/blob` + : `/container` + : "/"; + + blobContext.authenticationPath = reqPath; + if (isSecondary) { + const pos = blobContext.authenticationPath!.search(SECONDARY_SUFFIX); + blobContext.authenticationPath = + blobContext.authenticationPath!.substr(0, pos) + + blobContext.authenticationPath!.substr(pos + SECONDARY_SUFFIX.length); + } + + if (!account) { + const handlerError = + StorageErrorFactory.getInvalidQueryParameterValue(blobContext); + + logger.error( + `BlobStorageContextMiddleware: BlobStorageContextMiddleware: ${handlerError.message}`, + requestID + ); + + return next(handlerError); + } + + // validate conatainer name, when container name has value (not undefined or empty string) + // skip validate system container + if (container && !container.startsWith("$")) { + validateContainerName(blobContext, container); + } + + logger.info( + `BlobStorageContextMiddleware: Account=${account} Container=${container} Blob=${blob}`, + requestID + ); + next(); +} + +/** + * A middleware extract related blob service context. + * + * @export + * @param {Request} req An express compatible Request object + * @param {Response} res An express compatible Response object + * @param {NextFunction} next An express middleware next callback + */ +export function blobStorageContextMiddleware( + req: Request, + res: Response, + next: NextFunction, + skipApiVersionCheck?: boolean, + disableProductStyleUrl?: boolean, + loose?: boolean +): void { + // Set server header in every Azurite response + res.setHeader(HeaderConstants.SERVER, `Azurite-DataLake/${VERSION}`); + const requestID = uuid(); + const blobContext = new DataLakeContext(res.locals, DEFAULT_CONTEXT_PATH); + blobContext.startTime = new Date(); + blobContext.disableProductStyleUrl = disableProductStyleUrl; + blobContext.loose = loose; + blobContext.xMsRequestID = requestID; + + if (!skipApiVersionCheck) { + const apiVersion = req.header(HeaderConstants.X_MS_VERSION); + if (apiVersion !== undefined) { + checkApiVersion(apiVersion, ValidAPIVersions, blobContext); + } + } + + logger.info( + `BlobStorageContextMiddleware: RequestMethod=${req.method} RequestURL=${ + req.protocol + }://${req.hostname}${req.url} RequestHeaders:${JSON.stringify( + req.headers + )} ClientIP=${req.ip} Protocol=${req.protocol} HTTPVersion=${ + req.httpVersion + }`, + requestID + ); + + const [account, container, blob, originalBlob, isSecondary] = + extractStoragePartsFromPath(req.hostname, req.path, disableProductStyleUrl); + + blobContext.account = account; + blobContext.container = container; + blobContext.blob = blob; + blobContext.originalBlob = originalBlob; + blobContext.isSecondary = isSecondary; + + // Emulator's URL pattern is like http://hostname[:port]/account/container + // (or, alternatively, http[s]://account.localhost[:port]/container) + // Create a router to exclude account name from req.path, as url path in swagger doesn't include account + // Exclude account name from req.path for dispatchMiddleware + blobContext.dispatchPattern = container + ? blob + ? `/container/blob` + : `/container` + : "/"; + + blobContext.authenticationPath = req.path; + if (isSecondary) { + const pos = blobContext.authenticationPath.search(SECONDARY_SUFFIX); + blobContext.authenticationPath = + blobContext.authenticationPath.substr(0, pos) + + blobContext.authenticationPath.substr(pos + SECONDARY_SUFFIX.length); + } + + if (!account) { + const handlerError = + StorageErrorFactory.getInvalidQueryParameterValue(blobContext); + + logger.error( + `BlobStorageContextMiddleware: BlobStorageContextMiddleware: ${handlerError.message}`, + requestID + ); + + return next(handlerError); + } + + // validate conatainer name, when container name has value (not undefined or empty string) + // skip validate system container + if (container && !container.startsWith("$")) { + validateContainerName(blobContext, container); + } + + logger.info( + `BlobStorageContextMiddleware: Account=${account} Container=${container} Blob=${blob}`, + requestID + ); + next(); +} + +/** + * Extract storage account, container, and blob from URL path. + * + * @param {string} path + * @returns {([string | undefined, string | undefined, string | undefined, boolean | undefined])} + */ +export function extractStoragePartsFromPath( + hostname: string, + path: string, + disableProductStyleUrl?: boolean +): [ + string | undefined, + string | undefined, + string | undefined, + string | undefined, + boolean | undefined +] { + let account; + let container; + let blob; + let isSecondary = false; + + const normalizedPath = path.startsWith("/") ? path.substring(1) : path; // Remove starting "/" + + const parts = normalizedPath.split("/"); + + let urlPartIndex = 0; + const isIPAddress = IP_REGEX.test(hostname); + const isNoAccountHostName = NO_ACCOUNT_HOST_NAMES.has(hostname.toLowerCase()); + const firstDotIndex = hostname.indexOf("."); + // If hostname is not an IP address or a known host name, and has a dot inside, + // we assume user wants to access emulator with a production-like URL. + if ( + !disableProductStyleUrl && + !isIPAddress && + !isNoAccountHostName && + firstDotIndex > 0 + ) { + account = hostname.substring(0, firstDotIndex); + } else { + account = parts[urlPartIndex++]; + } + container = parts[urlPartIndex++]; + if (container === account) container = parts[urlPartIndex++]; + const originalBlob = parts.slice(urlPartIndex++).join("/"); + blob = decodeURIComponent(originalBlob).replace(/\\/g, "/"); // Azure Storage Server will replace "\" with "/" in the blob names + + if (account.endsWith(SECONDARY_SUFFIX)) { + account = account.substring(0, account.length - SECONDARY_SUFFIX.length); + isSecondary = true; + } + + if (account !== undefined) account = decodeURIComponent(account); + if (container !== undefined) container = decodeURIComponent(container); + return [account, container, blob, originalBlob, isSecondary]; +} diff --git a/src/dfs/persistence/IDataLakeMetadataStore.ts b/src/dfs/persistence/IDataLakeMetadataStore.ts new file mode 100644 index 000000000..cd7f9e4f8 --- /dev/null +++ b/src/dfs/persistence/IDataLakeMetadataStore.ts @@ -0,0 +1,237 @@ +import IBlobMetadataStore, { + BlobModel, + BlobPrefixModel, + BlockModel, + ContainerModel +} from "../../blob/persistence/IBlobMetadataStore"; +import ICleaner from "../../common/ICleaner"; +import IDataStore from "../../common/IDataStore"; +import IGCExtentProvider from "../../common/IGCExtentProvider"; +import * as Models from "../generated/artifacts/models"; +import Context from "../../blob/generated/Context"; + +/** + * Persistency layer metadata storage interface. + * + * TODO: Integrate cache layer to cache account, container & blob metadata. + * + * @export + * @interface IDataLakeMetadataStore + * @extends {IDataStore} + */ +export interface IDataLakeMetadataStore + extends IBlobMetadataStore, + IGCExtentProvider, + IDataStore, + ICleaner { + /** + * Set container properties. + * + * @param {Context} context + * @param {string} account + * @param {string} container + * @param {string} [properties] + * @param {Models.LeaseAccessConditions} [leaseAccessConditions] + * @param {Models.ModifiedAccessConditions} [modifiedAccessConditions] + * @returns {Promise} + * @memberof IBlobMetadataStore + */ + setContainerProperties( + context: Context, + account: string, + container: string, + properties: string, + leaseAccessConditions?: Models.LeaseAccessConditions, + modifiedAccessConditions?: Models.ModifiedAccessConditions + ): Promise; + + list( + lisDirectories: boolean | undefined, + context: Context, + account: string, + container: string, + delimiter?: string, + blob?: string, + prefix?: string, + maxResults?: number, + marker?: string, + includeSnapshots?: boolean, + includeUncommittedBlobs?: boolean + ): Promise<[BlobModel[], BlobPrefixModel[], string | undefined]>; + + /** + * Update blob block item in persistency layer. Will create if block doesn't exist. + * Will also create a uncommitted block blob. + * + * @param {BlockModel} block + * @param {Context} context + * @returns {Promise} + * @memberof IBlobMetadataStore + */ + appendData( + context: Context, + block: BlockModel, + leaseAccessConditions: Models.LeaseAccessConditions | undefined + ): Promise; + + /** + * Commit block list for a blob. + * + * @param {Context} context + * @param {BlobModel} blob + * @param {{ blockName: string; blockCommitType: string }[]} blockList + * @param {Models.LeaseAccessConditions} [leaseAccessConditions] + * @param {Models.ModifiedAccessConditions} [modifiedAccessConditions] + * @returns {Promise} + * @memberof IBlobMetadataStore + */ + flush( + context: Context, + blob: BlobModel, + blockList: { blockName: string; blockCommitType: string }[], + leaseAccessConditions?: Models.LeaseAccessConditions, + modifiedAccessConditions?: Models.ModifiedAccessConditions + ): Promise; + + /*************************************************************************** + * + * New DataLake specific functions + * + ***************************************************************************/ + /** + * Rename Directory + * + * @param {Context} context + * @param {string} account + * @param {string} sourceContainer + * @param {string} sourceDirectory + * @param {string} targetContainer + * @param {string} targetDirectory + * @param {Models.DirectoryRenameOptionalParams} options + * @returns {Promise} + * @memberof IBlobMetadataStore + */ + renameDirectory( + context: Context, + account: string, + sourceContainer: string, + sourceDirectory: string, + targetContainer: string, + targetDirectory: string, + options: Models.PathCreateOptionalParams + ): Promise; + + /** + * List paths in Directory + * + * @param {Context} context + * @param {string} account + * @param {string} container + * @param {string} directory + * @param {boolean} recursive + * @param {Models.FileSystemListPathsOptionalParams} options + * @returns {Promise} + * @memberof IBlobMetadataStore + */ + listPaths( + context: Context, + account: string, + container: string, + directory: string, + recursive: boolean, + options: Models.FileSystemListPathsOptionalParams + ): Promise<[Models.Path[], string | undefined]>; + + /** + * Delete Directory + * + * @param {Context} context + * @param {string} account + * @param {string} container + * @param {string} directory + * @param {boolean} recursiveDirectoryDelete + * @param {Models.DirectoryDeleteMethodOptionalParams} options + * @returns {Promise} + * @memberof IBlobMetadataStore + */ + deleteDirectory( + context: Context, + account: string, + container: string, + directory: string, + recursiveDirectoryDelete: boolean, + options: Models.PathDeleteMethodOptionalParams + ): Promise; + + /** + * Rename Blob + * + * @param {Context} context + * @param {string} account + * @param {string} sourceContainer + * @param {string} sourceBlob + * @param {string} targetContainer + * @param {string} targetBlob + * @param {Models.PathCreateOptionalParams} options + * @returns {Promise} + * @memberof IBlobMetadataStore + */ + renameBlob( + context: Context, + account: string, + sourceContainer: string, + sourceBlob: string, + targetContainer: string, + targetBlob: string, + options: Models.PathCreateOptionalParams + ): Promise; + + /** + * Gets a blob item from metadata store by account name, container name and blob name. + * Will return block list or page list as well for downloading. + * + * @param {Context} context + * @param {string} account + * @param {string} container + * @param {string} blob + * @param {(string | undefined)} snapshot + * @param {Models.LeaseAccessConditions} [leaseAccessConditions] Optional. Will validate lease if provided + * @param {Models.ModifiedAccessConditions} [modifiedAccessConditions] + * @returns {Promise} + * @memberof IBlobMetadataStore + */ + getModel( + context: Context, + account: string, + container: string, + blob: string, + forceExist: true, + leaseAccessConditions?: Models.LeaseAccessConditions, + modifiedAccessConditions?: Models.ModifiedAccessConditions, + validateRead?: boolean + ): Promise; + + getModel( + context: Context, + account: string, + container: string, + blob: string, + forceExist: false | undefined, + leaseAccessConditions?: Models.LeaseAccessConditions, + modifiedAccessConditions?: Models.ModifiedAccessConditions, + validateRead?: boolean + ): Promise; + + getModel( + context: Context, + account: string, + container: string, + blob: string, + forceExist?: boolean, + leaseAccessConditions?: Models.LeaseAccessConditions, + modifiedAccessConditions?: Models.ModifiedAccessConditions, + validateRead?: boolean + ): Promise; +} + +export default IDataLakeMetadataStore; diff --git a/src/dfs/persistence/LokiDataLakeMetadataStore.ts b/src/dfs/persistence/LokiDataLakeMetadataStore.ts new file mode 100644 index 000000000..9ea71ed04 --- /dev/null +++ b/src/dfs/persistence/LokiDataLakeMetadataStore.ts @@ -0,0 +1,845 @@ +import { + BlobModel, + BlobPrefixModel, + BlockModel, + ContainerModel, + PersistencyBlockModel +} from "../../blob/persistence/IBlobMetadataStore"; +import LokiBlobMetadataStore from "../../blob/persistence/LokiBlobMetadataStore"; +import { DEFAULT_LIST_BLOBS_MAX_RESULTS } from "../../blob/utils/constants"; +import IGCExtentProvider from "../../common/IGCExtentProvider"; +import { newEtag } from "../../common/utils/utils"; +import { validateReadConditions } from "../../blob/conditions/ReadConditionalHeadersValidator"; +import { validateWriteConditions } from "../../blob/conditions/WriteConditionalHeadersValidator"; +import StorageErrorFactory from "../errors/StorageErrorFactory"; +import * as Models from "../generated/artifacts/models"; +import Context from "../../blob/generated/Context"; +import BlobLeaseAdapter from "../../blob/lease/BlobLeaseAdapter"; +import BlobLeaseSyncer from "../../blob/lease/BlobLeaseSyncer"; +import BlobReadLeaseValidator from "../../blob/lease/BlobReadLeaseValidator"; +import BlobWriteLeaseSyncer from "../../blob/lease/BlobWriteLeaseSyncer"; +import BlobWriteLeaseValidator from "../../blob/lease/BlobWriteLeaseValidator"; +import ContainerLeaseAdapter from "../../blob/lease/ContainerLeaseAdapter"; +import ContainerReadLeaseValidator from "../../blob/lease/ContainerReadLeaseValidator"; +import { ILease } from "../../blob/lease/ILeaseState"; +import LeaseFactory from "../../blob/lease/LeaseFactory"; +import { removeSlash } from "../utils/utils"; +import IDataLakeMetadataStore from "./IDataLakeMetadataStore"; +import PageWithDelimiter from "../../blob/persistence/PageWithDelimiter"; +import BlobReferredExtentsAsyncIterator from "../../blob/persistence/BlobReferredExtentsAsyncIterator"; + +/** + * This is a metadata source implementation for blob based on loki DB. + * + * Notice that, following design is for emulator purpose only, and doesn't design for best performance. + * We may want to optimize the persistency layer performance in the future. Such as by distributing metadata + * into different collections, or make binary payload write as an append-only pattern. + * + * Loki DB includes following collections and documents: + * + * -- SERVICE_PROPERTIES_COLLECTION // Collection contains service properties + * // Default collection name is $SERVICES_COLLECTION$ + * // Each document maps to 1 account blob service + * // Unique document properties: accountName + * -- CONTAINERS_COLLECTION // Collection contains all containers + * // Default collection name is $CONTAINERS_COLLECTION$ + * // Each document maps to 1 container + * // Unique document properties: accountName, (container)name + * -- BLOBS_COLLECTION // Collection contains all blobs + * // Default collection name is $BLOBS_COLLECTION$ + * // Each document maps to a blob + * // Unique document properties: accountName, containerName, (blob)name, snapshot + * -- BLOCKS_COLLECTION // Block blob blocks collection includes all UNCOMMITTED blocks + * // Unique document properties: accountName, containerName, blobName, name, isCommitted + * + * @export + * @class LokiBlobMetadataStore + */ +export default class LokiDataLakeMetadataStore + extends LokiBlobMetadataStore + implements IDataLakeMetadataStore, IGCExtentProvider +{ + protected readonly PATHS_COLLECTION = "$PATHS_COLLECTION$"; + + public constructor(public readonly lokiDBPath: string) { + super(lokiDBPath); + } + + public async init(): Promise { + if (this.db.getCollection(this.PATHS_COLLECTION) === null) { + this.db.addCollection(this.PATHS_COLLECTION, { + indices: ["accountName", "containerName", "name"] // Optimize for find operation + }); + } + + super.init(); + } + + public iteratorExtents(): AsyncIterator { + return new BlobReferredExtentsAsyncIterator(this); + } + + /** + * Set container properties. + * + * @param {Context} context + * @param {string} account + * @param {string} container + * @param {string} properties + * @param {Models.LeaseAccessConditions} [leaseAccessConditions] + * @param {Models.ModifiedAccessConditions} [modifiedAccessConditions] + * @returns {Promise} + * @memberof IBlobMetadataStore + */ + async setContainerProperties( + context: Context, + account: string, + container: string, + properties: string, + leaseAccessConditions?: Models.LeaseAccessConditions, + modifiedAccessConditions?: Models.ModifiedAccessConditions + ): Promise { + const coll = this.db.getCollection(this.CONTAINERS_COLLECTION); + const doc = await this.getContainerWithLeaseUpdated( + account, + container, + context, + false + ); + + validateWriteConditions(context, modifiedAccessConditions, doc); + + if (!doc) { + throw StorageErrorFactory.getContainerNotFound(context); + } + + new ContainerReadLeaseValidator(leaseAccessConditions).validate( + new ContainerLeaseAdapter(doc), + context + ); + + doc.fileSystemProperties = properties; + coll.update(doc); + return doc; + } + + public async list( + lisDirectories: boolean | undefined, + context: Context, + account: string, + container: string, + delimiter?: string, + blob?: string, + prefix: string = "", + maxResults: number = DEFAULT_LIST_BLOBS_MAX_RESULTS, + marker: string = "", + includeSnapshots?: boolean, + includeUncommittedBlobs?: boolean + ): Promise<[BlobModel[], BlobPrefixModel[], string | undefined]> { + const query: any = {}; + if (prefix !== "") { + query.name = { $regex: `^${this.escapeRegex(prefix)}` }; + } + if (blob !== undefined) { + query.name = blob; + } + if (account !== undefined) { + query.accountName = account; + } + if (container !== undefined) { + query.containerName = container; + } + + if (lisDirectories !== undefined) { + query.isDirectory = lisDirectories; + } + + if (lisDirectories !== false) { + includeSnapshots = true; + includeUncommittedBlobs = true; + } + + const coll = this.db.getCollection(this.BLOBS_COLLECTION); + const page = new PageWithDelimiter( + maxResults, + delimiter, + prefix + ); + const readPage = async (offset: number): Promise => { + return coll + .chain() + .find(query) + .where((obj) => { + return obj.name > marker!; + }) + .where((obj) => { + return includeSnapshots ? true : obj.snapshot.length === 0; + }) + .where((obj) => { + return includeUncommittedBlobs ? true : obj.isCommitted; + }) + .sort((obj1, obj2) => { + if (obj1.name === obj2.name) return 0; + if (obj1.name > obj2.name) return 1; + return -1; + }) + .offset(offset) + .limit(maxResults) + .data(); + }; + + const nameItem = (item: BlobModel) => { + return item.name; + }; + + const [blobItems, blobPrefixes, nextMarker] = await page.fill( + readPage, + nameItem + ); + + let blobModels = blobItems.map((doc) => { + doc.properties.contentMD5 = this.restoreUint8Array( + doc.properties.contentMD5 + ); + return LeaseFactory.createLeaseState( + new BlobLeaseAdapter(doc), + context + ).sync(new BlobLeaseSyncer(doc)); + }); + blobModels = blobModels.filter((model) => + this.validateExpireConditionsDfs(context, model, false) + ); + return [blobModels, blobPrefixes, nextMarker]; + } + + /** + * Update blob block item in persistency layer. Will create if block doesn't exist. + * Will also create a uncommitted block blob. + * + * @param {BlockModel} block + * @param {Context} context + * @returns {Promise} + * @memberof LokiBlobMetadataStore + */ + public async appendData( + context: Context, + block: BlockModel, + leaseAccessConditions?: Models.LeaseAccessConditions + ): Promise { + await this.checkContainerExist( + context, + block.accountName, + block.containerName + ); + + const blobColl = this.db.getCollection(this.BLOBS_COLLECTION); + const blobDoc = blobColl.findOne({ + accountName: block.accountName, + containerName: block.containerName, + name: block.blobName + }); + + const valid = this.validateExpireConditionsDfs(context, blobDoc, false); + if (!blobDoc || !valid) { + const etag = newEtag(); + const newBlob: BlobModel = { + deleted: false, + accountName: block.accountName, + containerName: block.containerName, + name: block.blobName, + properties: { + creationTime: context.startTime, + lastModified: context.startTime!, + etag, + contentLength: 0, + blobType: Models.BlobType.BlockBlob + }, + snapshot: "", + isCommitted: false, + }; + blobColl.insert(newBlob); + } else { + if (blobDoc.properties.blobType !== Models.BlobType.AppendBlob) { + throw StorageErrorFactory.getBlobInvalidBlobType(context); + } + + LeaseFactory.createLeaseState(new BlobLeaseAdapter(blobDoc), context) + .validate(new BlobWriteLeaseValidator(leaseAccessConditions)) + .sync(new BlobWriteLeaseSyncer(blobDoc)); + } + + const coll = this.db.getCollection(this.BLOCKS_COLLECTION); + const blockDoc = coll.findOne({ + accountName: block.accountName, + containerName: block.containerName, + blobName: block.blobName, + name: block.name, + isCommitted: block.isCommitted + }); + + if (blockDoc) { + coll.remove(blockDoc); + } + + delete (block as any).$loki; + coll.insert(block); + } + + /** + * Commit block list for a blob. + * + * @param {Context} context + * @param {BlobModel} blob + * @param {{ blockName: string; blockCommitType: string }[]} blockList + * @param {Models.LeaseAccessConditions} [leaseAccessConditions] + * @param {Models.ModifiedAccessConditions} [modifiedAccessConditions] + * @returns {Promise} + * @memberof LokiBlobMetadataStore + */ + public async flush( + context: Context, + blob: BlobModel, + blockList: { blockName: string; blockCommitType: string }[], + leaseAccessConditions?: Models.LeaseAccessConditions, + modifiedAccessConditions?: Models.ModifiedAccessConditions + ): Promise { + const coll = this.db.getCollection(this.BLOBS_COLLECTION); + const doc = await this.getBlobWithLeaseUpdated( + blob.accountName, + blob.containerName, + blob.name, + blob.snapshot, + context, + // XStore allows commit block list with empty block list to create a block blob without stage block call + // In this case, there will no existing blob doc exists + false + ); + + this.validateExpireConditionsDfs(context, doc, true); + validateWriteConditions(context, modifiedAccessConditions, doc); + + // Create if not exists + if ( + modifiedAccessConditions && + modifiedAccessConditions.ifNoneMatch === "*" && + doc && + doc.isCommitted + ) { + throw StorageErrorFactory.getBlobAlreadyExists(context); + } + + let lease: ILease | undefined; + if (doc) { + if (doc.properties.blobType !== Models.BlobType.AppendBlob) { + throw StorageErrorFactory.getBlobInvalidBlobType(context); + } + + lease = new BlobLeaseAdapter(doc); + new BlobWriteLeaseValidator(leaseAccessConditions).validate( + lease, + context + ); + } + + // Get all blocks in persistency layer + const blockColl = this.db.getCollection(this.BLOCKS_COLLECTION); + const pUncommittedBlocks = blockColl + .chain() + .find({ + accountName: blob.accountName, + containerName: blob.containerName, + blobName: blob.name + }) + .data(); + + const pUncommittedBlocksMap: Map = new Map(); // persistencyUncommittedBlocksMap + for (const pBlock of pUncommittedBlocks) { + if (!pBlock.isCommitted) { + pUncommittedBlocksMap.set(pBlock.name, pBlock); + } + } + + const selectedBlockList: PersistencyBlockModel[] = + doc && doc.committedBlocksInOrder ? doc.committedBlocksInOrder : []; + for (const block_1 of blockList) { + const pUncommittedBlock = pUncommittedBlocksMap.get(block_1.blockName); + if (pUncommittedBlock === undefined) { + throw StorageErrorFactory.getInvalidBlockList(context); + } else { + selectedBlockList.push(pUncommittedBlock); + } + } + + if (doc) { + // Commit block list + doc.properties.blobType = blob.properties.blobType; + doc.properties.lastModified = blob.properties.lastModified; + doc.committedBlocksInOrder = selectedBlockList; + doc.isCommitted = true; + doc.metadata = blob.metadata; + doc.properties.accessTier = blob.properties.accessTier; + doc.properties.accessTierInferred = blob.properties.accessTierInferred; + doc.properties.etag = blob.properties.etag; + doc.properties.cacheControl = blob.properties.cacheControl; + doc.properties.contentType = blob.properties.contentType; + doc.properties.contentMD5 = blob.properties.contentMD5; + doc.properties.contentEncoding = blob.properties.contentEncoding; + doc.properties.contentLanguage = blob.properties.contentLanguage; + doc.properties.contentDisposition = blob.properties.contentDisposition; + doc.properties.contentLength = selectedBlockList + .map((block) => block.size) + .reduce((total, val) => { + return total + val; + }, 0); + + // set lease state to available if it's expired + if (lease) { + new BlobWriteLeaseSyncer(doc).sync(lease); + } + + coll.update(doc); + } else { + blob.committedBlocksInOrder = selectedBlockList; + blob.properties.contentLength = selectedBlockList + .map((block) => block.size) + .reduce((total, val) => { + return total + val; + }, 0); + coll.insert(blob); + } + + blockColl.findAndRemove({ + accountName: blob.accountName, + containerName: blob.containerName, + blobName: blob.name + }); + } + + /** + * List paths in Directory + * + * @param {Context} context + * @param {string} account + * @param {string} container + * @param {string} directory + * @param {boolean} recursive + * @param {Models.FileSystemListPathsOptionalParams} options + * @returns {Promise} + * @memberof IBlobMetadataStore + */ + async listPaths( + context: Context, + account: string, + container: string, + directory: string, + recursive: boolean, + options: Models.FileSystemListPathsOptionalParams + ): Promise<[Models.Path[], string | undefined]> { + directory = removeSlash(directory); + const paths: Models.Path[] = []; + + if (directory) + await this.getModel(context, account, container, directory, true); + const [blobs, , nextMarker] = await this.list( + undefined, + context, + account, + container, + recursive ? undefined : "/", + undefined, + directory ? directory + "/" : directory, + options.maxResults, + options.continuation + ); + blobs.forEach((blob) => { + paths.push({ + name: blob.name, + isDirectory: blob.isDirectory ? true : undefined, + lastModified: blob.properties.lastModified, + etag: blob.properties.etag, + contentLength: blob.properties.contentLength, + owner: blob.owner, + group: blob.group, + permissions: blob.permissions + }); + }); + + return [paths, nextMarker]; + } + + /** + * Rename Directory + * + * @param {Context} context + * @param {string} account + * @param {string} sourceContainer + * @param {string} sourceDirectory + * @param {string} targetContainer + * @param {string} targetDirectory + * @param {Models.DirectoryRenameOptionalParams} options + * @returns {Promise} + * @memberof IBlobMetadataStore + */ + public async renameDirectory( + context: Context, + account: string, + sourceContainer: string, + sourceDirectory: string, + targetContainer: string, + targetDirectory: string, + options: Models.PathCreateOptionalParams + ): Promise { + sourceDirectory = removeSlash(sourceDirectory); + targetDirectory = removeSlash(targetDirectory); + + const dirModel = await this.getModel( + context, + account, + targetContainer, + targetDirectory, + false + ); + + if ( + options.modifiedAccessConditions && + options.modifiedAccessConditions.ifNoneMatch === "*" && + dirModel + ) { + throw StorageErrorFactory.getBlobAlreadyExists(context); + } + + const [paths] = await this.listPaths( + context, + account, + sourceContainer, + sourceDirectory, + true, + options + ); + + paths.forEach(async (path) => { + await this.rename( + path.isDirectory!, + context, + account, + sourceContainer, + path.name!, + targetContainer, + targetDirectory + path.name!.substring(sourceDirectory.length), + options + ); + }); + + await this.rename( + true, + context, + account, + sourceContainer, + sourceDirectory, + targetContainer, + targetDirectory, + options + ); + const res = await this.getModel( + context, + account, + targetContainer, + targetDirectory, + true + ); + return res!; + } + + /** + * Delete Directory + * + * @param {Context} context + * @param {string} account + * @param {string} container + * @param {string} directory + * @param {boolean} recursiveDirectoryDelete + * @param {Models.DirectoryDeleteMethodOptionalParams} options + * @returns {Promise} + * @memberof IBlobMetadataStore + */ + public async deleteDirectory( + context: Context, + account: string, + container: string, + directory: string, + recursiveDirectoryDelete: boolean, + options: Models.PathDeleteMethodOptionalParams + ): Promise { + directory = removeSlash(directory); + await this.checkContainerExist(context, account, container); + + const dir: BlobModel = await this.db + .getCollection(this.BLOBS_COLLECTION) + .findOne({ + accountName: account, + containerName: container, + name: directory + }); + + validateWriteConditions(context, options.modifiedAccessConditions, dir); + + if (dir === null || dir === undefined) { + throw StorageErrorFactory.getBlobNotFound(context); + } + + const [blobs] = await this.list( + undefined, + context, + account, + container, + undefined, + undefined, + directory ? directory + "/" : directory, + DEFAULT_LIST_BLOBS_MAX_RESULTS, + undefined, + true, + true + ); + + if (blobs.length > 0 && !recursiveDirectoryDelete) { + throw StorageErrorFactory.getInvalidOperation( + context, + "Can't Delete non empty folder with non recursive flag" + ); + } else { + const options: Models.PathDeleteMethodOptionalParams = { + deleteSnapshots: Models.DeleteSnapshotsOptionType.Include + }; + + for (const blob of blobs) { + await this.deleteBlob( + context, + account, + container, + blob.name, + options + ); + } + } + + await this.deleteBlob( + context, + account, + container, + dir.name, + options + ); + } + + /** + * Rename Blob + * + * @param {Context} context + * @param {string} account + * @param {string} container + * @param {string} source + * @param {string} target + * @param {Models.BlobDeleteMethodOptionalParams} options + * @returns {Promise} + * @memberof LokiBlobMetadataStore + */ + public async renameBlob( + context: Context, + account: string, + sourceContainer: string, + sourceBlob: string, + targetContainer: string, + targetBlob: string, + options: Models.PathCreateOptionalParams + ): Promise { + return this.rename( + false, + context, + account, + sourceContainer, + sourceBlob, + targetContainer, + targetBlob, + options + ); + } + + public async rename( + isDirectory: boolean, + context: Context, + account: string, + sourceContainer: string, + sourceBlob: string, + targetContainer: string, + targetBlob: string, + options: Models.PathCreateOptionalParams + ): Promise { + const target = await this.getModel( + context, + account, + targetContainer, + targetBlob, + false, + options.leaseAccessConditions, + options.modifiedAccessConditions, + false + ); + + validateWriteConditions( + context, + options.modifiedAccessConditions, + target + ); + + if ( + options.modifiedAccessConditions && + options.modifiedAccessConditions.ifNoneMatch === "*" && + target + ) { + throw StorageErrorFactory.getBlobAlreadyExists(context); + } + + if (target) { + isDirectory + ? await this.deleteDirectory( + context, + account, + targetContainer, + targetBlob, + true, + options + ) + : await this.deleteBlob( + context, + account, + targetContainer, + targetBlob, + options + ); + } + + const model = await this.getModel( + context, + account, + sourceContainer, + sourceBlob + ); + + const newModel: BlobModel = { + ...model, + containerName: targetContainer, + name: targetBlob + }; + + await this.createBlob( + context, + newModel, + options.leaseAccessConditions, + options.modifiedAccessConditions + ); + + const coll = this.db.getCollection(this.BLOBS_COLLECTION); + coll.findAndRemove({ + accountName: account, + containerName: sourceContainer, + name: sourceBlob + }); + return model; + } + + /** + * Gets a blob item from persistency layer by container name and blob name. + * Will return block list or page list as well for downloading. + * + * @param {Context} context + * @param {string} account + * @param {string} container + * @param {string} blob + * @param {string} [snapshot=""] + * @param {Models.LeaseAccessConditions} [leaseAccessConditions] + * @param {Models.ModifiedAccessConditions} [modifiedAccessConditions] + * @returns {Promise} + * @memberof LokiBlobMetadataStore + */ + getModel( + context: Context, + account: string, + container: string, + blob: string, + forceExist?: true, + leaseAccessConditions?: Models.LeaseAccessConditions, + modifiedAccessConditions?: Models.ModifiedAccessConditions, + validateRead?: boolean + ): Promise; + + getModel( + context: Context, + account: string, + container: string, + blob: string, + forceExist: false, + leaseAccessConditions?: Models.LeaseAccessConditions, + modifiedAccessConditions?: Models.ModifiedAccessConditions, + validateRead?: boolean + ): Promise; + + public async getModel( + context: Context, + account: string, + container: string, + blob: string, + forceExists: boolean = true, + leaseAccessConditions?: Models.LeaseAccessConditions, + modifiedAccessConditions?: Models.ModifiedAccessConditions, + validateRead: boolean = true + ): Promise { + const doc = await this.getBlobWithLeaseUpdated( + account, + container, + blob, + "", + context, + false, + true + ); + + if (validateRead) { + validateReadConditions(context, modifiedAccessConditions, doc); + } + + if (!doc) { + if (!forceExists) return undefined; + throw StorageErrorFactory.getBlobNotFound(context); + } + + new BlobReadLeaseValidator(leaseAccessConditions).validate( + new BlobLeaseAdapter(doc), + context + ); + + return doc; + } + + private validateExpireConditionsDfs( + context: Context | undefined, + model: BlobModel | undefined, + throwError: boolean + ): boolean { + const now = new Date(); + if ( + model && + model.properties.expiresOn !== undefined && + model.properties.expiresOn < now + ) { + const coll = this.db.getCollection(this.BLOBS_COLLECTION); + coll.remove(model); + if (throwError && context !== undefined) { + throw StorageErrorFactory.getBlobNotFound(context); + } + + return false; + } + + return true; + } +} diff --git a/src/dfs/persistence/SqlDataLakeMetadataStore.ts b/src/dfs/persistence/SqlDataLakeMetadataStore.ts new file mode 100644 index 000000000..f9f7a8fc5 --- /dev/null +++ b/src/dfs/persistence/SqlDataLakeMetadataStore.ts @@ -0,0 +1,796 @@ +import { Op } from "sequelize"; + +import StorageErrorFactory from "../errors/StorageErrorFactory"; +import * as Models from "../generated/artifacts/models"; +import Context from "../../blob/generated/Context"; +import { removeSlash } from "../utils/utils"; +import SqlBlobMetadataStore, { + BlobsModel, + BlocksModel, + ContainersModel +} from "../../blob/persistence/SqlBlobMetadataStore"; +import IDataLakeMetadataStore from "./IDataLakeMetadataStore"; +import { + BlobModel, + BlobPrefixModel, + BlockModel, + ContainerModel, + PersistencyBlockModel +} from "../../blob/persistence/IBlobMetadataStore"; +import { validateWriteConditions } from "../../blob/conditions/WriteConditionalHeadersValidator"; +import LeaseFactory from "../../blob/lease/LeaseFactory"; +import ContainerReadLeaseValidator from "../../blob/lease/ContainerReadLeaseValidator"; +import { DEFAULT_LIST_BLOBS_MAX_RESULTS } from "../../blob/utils/constants"; +import BlobLeaseAdapter from "../../blob/lease/BlobLeaseAdapter"; +import BlobLeaseSyncer from "../../blob/lease/BlobLeaseSyncer"; +import PageWithDelimiter from "../../blob/persistence/PageWithDelimiter"; +import BlobWriteLeaseValidator from "../../blob/lease/BlobWriteLeaseValidator"; +import BlobWriteLeaseSyncer from "../../blob/lease/BlobWriteLeaseSyncer"; +import { validateReadConditions } from "../../blob/conditions/ReadConditionalHeadersValidator"; +import BlobReadLeaseValidator from "../../blob/lease/BlobReadLeaseValidator"; + +/** + * A SQL based Blob metadata storage implementation based on Sequelize. + * Refer to CONTRIBUTION.md for how to setup SQL database environment. + * + * @export + * @class SqlDataLakeMetadataStore + * @implements {IBlobMetadataStore} + */ +export default class SqlDataLakeMetadataStore + extends SqlBlobMetadataStore + implements IDataLakeMetadataStore +{ + /** + * Set container properties. + * + * @param {Context} context + * @param {string} account + * @param {string} container + * @param {string} properties + * @param {Models.LeaseAccessConditions} [leaseAccessConditions] + * @param {Models.ModifiedAccessConditions} [modifiedAccessConditions] + * @returns {Promise} + * @memberof IBlobMetadataStore + */ + async setContainerProperties( + context: Context, + account: string, + container: string, + properties: string, + leaseAccessConditions?: Models.LeaseAccessConditions, + modifiedAccessConditions?: Models.ModifiedAccessConditions + ): Promise { + return await this.sequelize.transaction(async (t) => { + /* Transaction starts */ + const findResult = await ContainersModel.findOne({ + where: { + accountName: account, + containerName: container + }, + transaction: t + }); + + if (findResult === null || findResult === undefined) { + throw StorageErrorFactory.getContainerNotFound(context); + } + + const containerModel = this.convertDbModelToContainerModel(findResult); + validateWriteConditions( + context, + modifiedAccessConditions, + containerModel + ); + + LeaseFactory.createLeaseState( + this.convertDbModelToLease(findResult), + context + ).validate(new ContainerReadLeaseValidator(leaseAccessConditions)); + + await ContainersModel.update( + { + properties + }, + { + where: { + accountName: account, + containerName: container + }, + transaction: t + } + ); + + containerModel.fileSystemProperties = properties; + return containerModel; + /* Transaction ends */ + }); + } + + /** + * List paths in Directory + * + * @param {Context} context + * @param {string} account + * @param {string} container + * @param {string} directory + * @param {boolean} recursive + * @param {Models.FileSystemListPathsOptionalParams} options + * @returns {Promise} + * @memberof IBlobMetadataStore + */ + async listPaths( + context: Context, + account: string, + container: string, + directory: string, + recursive: boolean, + options: Models.FileSystemListPathsOptionalParams + ): Promise<[Models.Path[], string | undefined]> { + directory = removeSlash(directory); + const paths: Models.Path[] = []; + + if (directory) { + const model = await this.getModel( + context, + account, + container, + directory, + true + ); + + if (!model.isDirectory) { + throw StorageErrorFactory.getPathConflict(context); + } + } + + const [blobs, , nextMarker] = await this.list( + undefined, + context, + account, + container, + recursive ? undefined : "/", + undefined, + directory ? directory + "/" : undefined, + options.maxResults, + options.continuation + ); + blobs.forEach((blob) => { + paths.push({ + name: blob.name, + isDirectory: blob.isDirectory ? true : undefined, + lastModified: blob.properties.lastModified, + etag: blob.properties.etag, + contentLength: blob.properties.contentLength, + owner: blob.owner, + group: blob.group, + permissions: blob.permissions + }); + }); + + return [paths, nextMarker]; + } + + /** + * Rename Directory + * + * @param {Context} context + * @param {string} account + * @param {string} sourceContainer + * @param {string} sourceDirectory + * @param {string} targetContainer + * @param {string} targetDirectory + * @param {Models.DirectoryRenameOptionalParams} options + * @returns {Promise} + * @memberof IBlobMetadataStore + */ + public async renameDirectory( + context: Context, + account: string, + sourceContainer: string, + sourceDirectory: string, + targetContainer: string, + targetDirectory: string, + options: Models.PathCreateOptionalParams + ): Promise { + sourceDirectory = removeSlash(sourceDirectory); + targetDirectory = removeSlash(targetDirectory); + + const dirModel = await this.getModel( + context, + account, + targetContainer, + targetDirectory, + false + ); + + if ( + options.modifiedAccessConditions && + options.modifiedAccessConditions.ifNoneMatch === "*" && + dirModel + ) { + throw StorageErrorFactory.getBlobAlreadyExists(context); + } + + const [paths] = await this.listPaths( + context, + account, + sourceContainer, + sourceDirectory, + true, + options + ); + + paths.forEach(async (path) => { + await this.rename( + path.isDirectory!, + context, + account, + sourceContainer, + path.name!, + targetContainer, + targetDirectory + path.name!.substring(sourceDirectory.length), + options + ); + }); + + await this.rename( + true, + context, + account, + sourceContainer, + sourceDirectory, + targetContainer, + targetDirectory, + options + ); + const res = await this.getModel( + context, + account, + targetContainer, + targetDirectory, + true + ); + return res!; + } + + /** + * Delete Directory + * + * @param {Context} context + * @param {string} account + * @param {string} container + * @param {string} directory + * @param {boolean} recursiveDirectoryDelete + * @param {Models.DirectoryDeleteMethodOptionalParams} options + * @returns {Promise} + * @memberof IBlobMetadataStore + */ + public async deleteDirectory( + context: Context, + account: string, + container: string, + directory: string, + recursiveDirectoryDelete: boolean, + options: Models.PathDeleteMethodOptionalParams + ): Promise { + await this.sequelize.transaction(async (t) => { + await this.assertContainerExists(context, account, container, t); + + const directoryFindResult = await BlobsModel.findOne({ + where: { + accountName: account, + containerName: container, + blobName: directory, + isDirectory: true + }, + transaction: t + }); + + validateWriteConditions( + context, + options.modifiedAccessConditions, + directoryFindResult + ? this.convertDbModelToBlobModel(directoryFindResult) // TODO: Reduce double convert + : undefined + ); + + if (directoryFindResult === null || directoryFindResult === undefined) { + throw StorageErrorFactory.getBlobNotFound(context); + } + + const [blobs] = await this.list( + undefined, + context, + account, + container, + undefined, + undefined, + directory ? directory + "/" : directory, + DEFAULT_LIST_BLOBS_MAX_RESULTS, + undefined, + true, + true + ); + + if (blobs.length > 1 && !recursiveDirectoryDelete) { + throw StorageErrorFactory.getInvalidOperation( + context, + "Can't Delete non empty folder with non recursive flag" + ); + } else { + const options: Models.PathDeleteMethodOptionalParams = { + deleteSnapshots: Models.DeleteSnapshotsOptionType.Include + }; + + for (const blob of blobs) { + await this.deleteBlob( + context, + account, + container, + blob.name, + options + ); + } + } + + await this.deleteBlob(context, account, container, directory, options); + }); + } + + public async list( + lisDirectories: boolean | undefined, + context: Context, + account: string, + container: string, + delimiter?: string, + blob?: string, + prefix: string = "", + maxResults: number = DEFAULT_LIST_BLOBS_MAX_RESULTS, + marker?: string, + includeSnapshots?: boolean, + includeUncommittedBlobs?: boolean + ): Promise<[BlobModel[], BlobPrefixModel[], any | undefined]> { + return await this.sequelize.transaction(async (t) => { + await this.assertContainerExists(context, account, container, t); + + const whereQuery: any = { + accountName: account, + containerName: container + }; + + if (blob !== undefined) { + whereQuery.blobName = blob; + } else { + if (prefix.length > 0) { + whereQuery.blobName = { + [Op.like]: `${prefix}%` + }; + } + + if (marker !== undefined) { + if (whereQuery.blobName !== undefined) { + whereQuery.blobName[Op.gt] = marker; + } else { + whereQuery.blobName = { + [Op.gt]: marker + }; + } + } + } + if (lisDirectories !== false) { + includeSnapshots = true; + includeUncommittedBlobs = true; + } + if (lisDirectories !== undefined) { + whereQuery.isDirectory = lisDirectories; + } + if (!includeSnapshots) { + whereQuery.snapshot = ""; + } + if (!includeUncommittedBlobs) { + whereQuery.isCommitted = true; + } + + whereQuery.deleting = 0; + const leaseUpdateMapper = (model: BlobsModel) => { + const blobModel = this.convertDbModelToBlobModel(model); + return LeaseFactory.createLeaseState( + new BlobLeaseAdapter(blobModel), + context + ).sync(new BlobLeaseSyncer(blobModel)); + }; + + // fill the page by possibly querying multiple times + const page = new PageWithDelimiter( + maxResults, + delimiter, + prefix + ); + + const nameItem = (item: BlobsModel): string => { + return this.getModelValue(item, "blobName", true); + }; + + const readPage = async (off: number): Promise => { + return await BlobsModel.findAll({ + where: whereQuery as any, + order: [["blobName", "ASC"]], + transaction: t, + limit: maxResults, + offset: off + }); + }; + + const [blobItems, blobPrefixes, nextMarker] = await page.fill( + readPage, + nameItem + ); + + const blobModels = blobItems.map(leaseUpdateMapper); + return [blobModels, blobPrefixes, nextMarker]; + }); + } + + public async appendData( + context: Context, + block: BlockModel, + leaseAccessConditions?: Models.LeaseAccessConditions + ): Promise { + await this.sequelize.transaction(async (t) => { + await this.assertContainerExists( + context, + block.accountName, + block.containerName, + t + ); + + const blobFindResult = await BlobsModel.findOne({ + where: { + accountName: block.accountName, + containerName: block.containerName, + blobName: block.blobName, + snapshot: "" + }, + transaction: t + }); + + const blobModel: BlobModel | undefined = blobFindResult + ? this.convertDbModelToBlobModel(blobFindResult) + : undefined; + if (blobModel !== undefined) { + if (blobModel.isCommitted === true) { + LeaseFactory.createLeaseState( + new BlobLeaseAdapter(blobModel), + context + ).validate(new BlobWriteLeaseValidator(leaseAccessConditions)); + } + } else { + throw StorageErrorFactory.getBlobNotFound(context); + } + + await BlocksModel.upsert( + { + accountName: block.accountName, + containerName: block.containerName, + blobName: block.blobName, + blockName: block.name, + size: block.size, + persistency: this.serializeModelValue(block.persistency) + }, + { transaction: t } + ); + }); + } + + public async flush( + context: Context, + blob: BlobModel, + blockList: { blockName: string }[], + leaseAccessConditions?: Models.LeaseAccessConditions, + modifiedAccessConditions?: Models.ModifiedAccessConditions + ): Promise { + await this.sequelize.transaction(async (t) => { + await this.assertContainerExists( + context, + blob.accountName, + blob.containerName, + t + ); + + const pUncommittedBlocksMap: Map = + new Map(); // persistencyUncommittedBlocksMap + + const badRequestError = StorageErrorFactory.getInvalidBlockList(context); + + const blobFindResult = await BlobsModel.findOne({ + where: { + accountName: blob.accountName, + containerName: blob.containerName, + blobName: blob.name, + snapshot: blob.snapshot, + isCommitted: true + }, + transaction: t + }); + + const blobModel: BlobModel | undefined = blobFindResult + ? this.convertDbModelToBlobModel(blobFindResult) + : undefined; + validateWriteConditions(context, modifiedAccessConditions, blobModel); + + let creationTime = blob.properties.creationTime || context.startTime; + + if (blobModel !== undefined) { + // Create if not exists + if ( + modifiedAccessConditions && + modifiedAccessConditions.ifNoneMatch === "*" && + blobModel && + blobModel.isCommitted + ) { + throw StorageErrorFactory.getBlobAlreadyExists(context); + } + + creationTime = blobModel.properties.creationTime || creationTime; + + LeaseFactory.createLeaseState( + new BlobLeaseAdapter(blobModel), + context + ).validate(new BlobWriteLeaseValidator(leaseAccessConditions)); + } + + const blockFindResult = await BlocksModel.findAll({ + where: { + accountName: blob.accountName, + containerName: blob.containerName, + blobName: blob.name + }, + transaction: t + }); + for (const item of blockFindResult) { + const block: PersistencyBlockModel = { + name: this.getModelValue(item, "blockName", true), + size: this.getModelValue(item, "size", true), + persistency: this.deserializeModelValue(item, "persistency") + }; + pUncommittedBlocksMap.set(block.name, block); + } + + const selectedBlockList: PersistencyBlockModel[] = + blobModel && blobModel.committedBlocksInOrder + ? blobModel.committedBlocksInOrder + : []; + for (const block of blockList) { + const pUncommittedBlock = pUncommittedBlocksMap.get(block.blockName); + if (pUncommittedBlock === undefined) { + throw badRequestError; + } else { + selectedBlockList.push(pUncommittedBlock); + } + } + + const commitBlockBlob: BlobModel = { + ...blob, + deleted: false, + committedBlocksInOrder: selectedBlockList, + properties: { + ...blob.properties, + creationTime, + lastModified: blob.properties.lastModified || context.startTime, + contentLength: selectedBlockList + .map((block) => block.size) + .reduce((total, val) => { + return total + val; + }, 0) + } + }; + + new BlobWriteLeaseSyncer(commitBlockBlob).sync( + new BlobLeaseAdapter(commitBlockBlob) + ); + + await BlobsModel.upsert(this.convertBlobModelToDbModel(commitBlockBlob), { + transaction: t + }); + + await BlocksModel.destroy({ + where: { + accountName: blob.accountName, + containerName: blob.containerName, + blobName: blob.name + }, + transaction: t + }); + }); + } + + /** + * Rename Blob + * + * @param {Context} context + * @param {string} account + * @param {string} container + * @param {string} source + * @param {string} target + * @param {Models.BlobDeleteMethodOptionalParams} options + * @returns {Promise} + * @memberof LokiBlobMetadataStore + */ + public async renameBlob( + context: Context, + account: string, + sourceContainer: string, + sourceBlob: string, + targetContainer: string, + targetBlob: string, + options: Models.PathCreateOptionalParams + ): Promise { + return this.rename( + false, + context, + account, + sourceContainer, + sourceBlob, + targetContainer, + targetBlob, + options + ); + } + + public async rename( + isDirectory: boolean, + context: Context, + account: string, + sourceContainer: string, + sourceBlob: string, + targetContainer: string, + targetBlob: string, + options: Models.PathCreateOptionalParams + ): Promise { + return await this.sequelize.transaction(async (t) => { + const target = await this.getModel( + context, + account, + targetContainer, + targetBlob, + false, + options.leaseAccessConditions, + options.modifiedAccessConditions, + false + ); + + validateWriteConditions( + context, + options.modifiedAccessConditions, + target + ); + + if ( + options.modifiedAccessConditions && + options.modifiedAccessConditions.ifNoneMatch === "*" && + target + ) { + throw StorageErrorFactory.getBlobAlreadyExists(context); + } + + if (target) { + isDirectory + ? await this.deleteDirectory( + context, + account, + targetContainer, + targetBlob, + true, + options + ) + : await this.deleteBlob( + context, + account, + targetContainer, + targetBlob, + options + ); + } + + const model = await this.getModel( + context, + account, + sourceContainer, + sourceBlob + ); + + const newModel: BlobModel = { + ...model, + containerName: targetContainer, + name: targetBlob + }; + + await this.createBlob( + context, + newModel, + options.leaseAccessConditions, + options.modifiedAccessConditions + ); + + await this.deleteBlob(context, account, sourceContainer, sourceBlob, {}); + + return model; + }); + } + + /** + * Gets a blob item from persistency layer by container name and blob name. + * Will return block list or page list as well for downloading. + * + * @param {Context} context + * @param {string} account + * @param {string} container + * @param {string} blob + * @param {string} [snapshot=""] + * @param {Models.LeaseAccessConditions} [leaseAccessConditions] + * @param {Models.ModifiedAccessConditions} [modifiedAccessConditions] + * @returns {Promise} + * @memberof LokiBlobMetadataStore + */ + getModel( + context: Context, + account: string, + container: string, + blob: string, + forceExist?: true, + leaseAccessConditions?: Models.LeaseAccessConditions, + modifiedAccessConditions?: Models.ModifiedAccessConditions, + validateRead?: boolean + ): Promise; + + getModel( + context: Context, + account: string, + container: string, + blob: string, + forceExist: false, + leaseAccessConditions?: Models.LeaseAccessConditions, + modifiedAccessConditions?: Models.ModifiedAccessConditions, + validateRead?: boolean + ): Promise; + + public async getModel( + context: Context, + account: string, + container: string, + blob: string, + forceExists: boolean = true, + leaseAccessConditions?: Models.LeaseAccessConditions, + modifiedAccessConditions?: Models.ModifiedAccessConditions, + validateRead: boolean = true + ): Promise { + return await this.sequelize.transaction(async (t) => { + const doc = await this.getBlobWithLeaseUpdated( + account, + container, + blob, + "", + context, + false, + true, + t + ); + + if (validateRead) { + validateReadConditions(context, modifiedAccessConditions, doc); + } + + if (!doc) { + if (!forceExists) return undefined; + throw StorageErrorFactory.getBlobNotFound(context); + } + + new BlobReadLeaseValidator(leaseAccessConditions).validate( + new BlobLeaseAdapter(doc), + context + ); + + return doc; + }); + } +} diff --git a/src/dfs/storagefiledatalake/models.ts b/src/dfs/storagefiledatalake/models.ts new file mode 100644 index 000000000..ff71be66f --- /dev/null +++ b/src/dfs/storagefiledatalake/models.ts @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export declare interface PathAccessControlItem { + /** + * Indicates whether this is the default entry for the ACL. + */ + defaultScope: boolean; + /** + * Specifies which role this entry targets. + */ + accessControlType: AccessControlType; + /** + * Specifies the entity for which this entry applies. + */ + entityId: string; + /** + * Access control permissions. + */ + permissions: RolePermissions; +} + +export declare type AccessControlType = "user" | "group" | "mask" | "other"; + +export declare interface RolePermissions { + read: boolean; + write: boolean; + execute: boolean; +} + +export declare interface PathPermissions { + owner: RolePermissions; + group: RolePermissions; + other: RolePermissions; + stickyBit: boolean; + extendedAcls: boolean; +} + +export declare interface RemovePathAccessControlItem { + /** + * Indicates whether this is the default entry for the ACL. + */ + defaultScope: boolean; + /** + * Specifies which role this entry targets. + */ + accessControlType: AccessControlType; + /** + * Specifies the entity for which this entry applies. + * Must be omitted for types mask or other. It must also be omitted when the user or group is the owner. + */ + entityId?: string; +} diff --git a/src/dfs/storagefiledatalake/transforms.ts b/src/dfs/storagefiledatalake/transforms.ts new file mode 100644 index 000000000..484bdd772 --- /dev/null +++ b/src/dfs/storagefiledatalake/transforms.ts @@ -0,0 +1,288 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +import { + PathAccessControlItem, + PathPermissions, + RemovePathAccessControlItem, + RolePermissions +} from "./models"; + +export function toRolePermissions( + permissionsString: string +): RolePermissions | undefined { + if (permissionsString.length !== 3) { + return undefined; + } + + permissionsString = permissionsString.toLowerCase(); + + let read = false; + if (permissionsString[0] === "r") { + read = true; + } else if (permissionsString[0] !== "-") { + return undefined; + } + + let write = false; + if (permissionsString[1] === "w") { + write = true; + } else if (permissionsString[1] !== "-") { + return undefined; + } + + let execute = false; + if (permissionsString[2] === "x") { + execute = true; + } else if (permissionsString[2] !== "-") { + return undefined; + } + + return { read, write, execute }; +} + +const permissionsMap: Map = new Map(); +permissionsMap.set("0", "---"); +permissionsMap.set("1", "--x"); +permissionsMap.set("2", "-w-"); +permissionsMap.set("3", "-wx"); +permissionsMap.set("4", "r--"); +permissionsMap.set("5", "r-x"); +permissionsMap.set("6", "rw-"); +permissionsMap.set("7", "rwx"); + +function normalizePermissionsString( + permissionsString: string, + umask?: string +): string | undefined { + let permissionsNumber = parseInt(permissionsString, 8); + if (!isNaN(permissionsNumber) && permissionsString.length === 4) { + const umaskNumber = parseInt(umask || "not a number", 8); + if (umask !== undefined && umask.length == 4 && !isNaN(umaskNumber)) { + permissionsNumber = permissionsNumber & ~umaskNumber; + permissionsString = permissionsNumber.toString(8).padStart(4, "0"); + } + permissionsString = + permissionsMap.get(permissionsString[1])! + + permissionsMap.get(permissionsString[2]) + + permissionsMap.get(permissionsString[3]); + } + + if (permissionsString.length !== 9 && permissionsString.length !== 10) { + return undefined; + } + + if (permissionsString[8] === "t") { + const firstPart = permissionsString.substr(0, 8); + const lastPart = permissionsString.substr(9); + permissionsString = firstPart + "x" + lastPart; + } else if (permissionsString[8] === "T") { + const firstPart = permissionsString.substr(0, 8); + const lastPart = permissionsString.substr(9); + permissionsString = firstPart + "-" + lastPart; + } + + // Case insensitive + return permissionsString.toLowerCase(); +} + +export function toPermissions( + permissionsString: string, + umask?: string +): PathPermissions | undefined { + const permissionsStr = normalizePermissionsString(permissionsString, umask); + if (permissionsStr === undefined) return undefined; + permissionsString = permissionsStr; + let extendedAcls = false; + if (permissionsString.length === 10) { + if (permissionsString[9] === "+") { + extendedAcls = true; + } else { + return undefined; + } + } + + const owner = toRolePermissions(permissionsString.substr(0, 3)); + const group = toRolePermissions(permissionsString.substr(3, 3)); + const other = toRolePermissions(permissionsString.substr(6, 3)); + + if (owner === undefined || group === undefined || other === undefined) { + return undefined; + } + + return { + owner, + group, + other, + stickyBit: permissionsString[8] === "t" || permissionsString[8] === "T", + extendedAcls + }; +} + +export function toAccessControlItem( + aclItemString: string +): PathAccessControlItem | undefined { + if (aclItemString === "") return undefined; + + aclItemString = aclItemString.toLowerCase(); + + const parts = aclItemString.split(":"); + if (parts.length < 3 || parts.length > 4) { + return undefined; + } + + let defaultScope = false; + let index = 0; + if (parts.length === 4) { + if (parts[index] !== "default") return undefined; + defaultScope = true; + index++; + } + + const accessControlType = parts[index++]; + if ( + accessControlType !== "user" && + accessControlType !== "group" && + accessControlType !== "mask" && + accessControlType !== "other" + ) { + return undefined; + } + + const entityId = parts[index++]; + const permissions = toRolePermissions(parts[index++]); + + if (permissions === undefined) return undefined; + + return { + defaultScope, + accessControlType, + entityId, + permissions + }; +} + +export function toRemoveAccessControlItem( + aclItemString: string +): RemovePathAccessControlItem | undefined { + if (aclItemString === "") { + return undefined; + } + + aclItemString = aclItemString.toLowerCase(); + + const parts = aclItemString.split(":"); + if (parts.length < 1 || parts.length > 3) { + return undefined; + } + + if (parts.length === 3) { + if (parts[0] !== "default") { + return undefined; + } + } + + let defaultScope = false; + let index = 0; + if (parts[index] === "default") { + defaultScope = true; + index++; + } + + const accessControlType = parts[index++]; + if ( + accessControlType !== "user" && + accessControlType !== "group" && + accessControlType !== "mask" && + accessControlType !== "other" + ) { + return undefined; + } + + const entityId = parts[index++]; + + return { + defaultScope, + accessControlType, + entityId + }; +} + +export function toAcl(aclString?: string): PathAccessControlItem[] | undefined { + if (aclString === undefined || aclString === "" || aclString === null) { + return []; + } + + const acls = []; + const aclParts = aclString.split(","); + for (const aclPart of aclParts) { + const acl = toAccessControlItem(aclPart); + if (acl === undefined) return undefined; + acls.push(acl); + } + + return acls; +} + +export function toRemoveAcl( + aclString?: string +): RemovePathAccessControlItem[] | undefined { + if (aclString === undefined || aclString === "" || aclString === null) { + return []; + } + + const acls = []; + const aclParts = aclString.split(","); + for (const aclPart of aclParts) { + const acl = toRemoveAccessControlItem(aclPart); + if (acl === undefined) return undefined; + acls.push(acl); + } + + return acls; +} + +export function toAccessControlItemString(item: PathAccessControlItem): string { + const entityIdString = item.entityId !== undefined ? `:${item.entityId}` : ""; + const permissionsString = + item.permissions !== undefined + ? `:${toRolePermissionsString(item.permissions)}` + : ""; + return `${item.defaultScope ? "default:" : ""}${ + item.accessControlType + }${entityIdString}${permissionsString}`; +} + +export function toAclString(acl: PathAccessControlItem[]): string { + return acl.map(toAccessControlItemString).join(","); +} + +export function toRolePermissionsString( + p: RolePermissions, + stickyBit: boolean = false +): string { + return `${p.read ? "r" : "-"}${p.write ? "w" : "-"}${ + stickyBit ? (p.execute ? "t" : "T") : p.execute ? "x" : "-" + }`; +} + +export function toPermissionsString(permissions: PathPermissions): string { + return `${toRolePermissionsString( + permissions.owner + )}${toRolePermissionsString(permissions.group)}${toRolePermissionsString( + permissions.other, + permissions.stickyBit + )}${permissions.extendedAcls ? "+" : ""}`; +} + +export function permissionsStringToAclString( + permissions: string +): string | undefined { + const normalizedPermissions = normalizePermissionsString(permissions, "0000"); + if (normalizedPermissions === undefined) return undefined; + + return ( + `user::${normalizedPermissions.substring(0, 3)},` + + `group::${normalizedPermissions.substring(3, 6)},` + + `other::${normalizedPermissions.substring(6, 9)}` + ); +} diff --git a/src/dfs/utils/constants.ts b/src/dfs/utils/constants.ts new file mode 100644 index 000000000..9e098f96c --- /dev/null +++ b/src/dfs/utils/constants.ts @@ -0,0 +1,208 @@ +import { StoreDestinationArray } from "../../common/persistence/IExtentStore"; +import * as Models from "../generated/artifacts/models"; +import { execSync, ExecSyncOptionsWithStringEncoding } from "child_process"; +import os from "os"; + +export const KB: number = 1024; +export const MB: number = KB * 1024; +export const GB: number = MB * 1024; +export const TB: number = GB * 1024; + +export const FILE_MAX_SINGLE_UPLOAD_THRESHOLD: number = 100 * MB; +export const FILE_UPLOAD_MAX_CHUNK_SIZE: number = 4000 * MB; +export const MAX_APPEND_BLOB_BLOCK_SIZE = FILE_MAX_SINGLE_UPLOAD_THRESHOLD; +export const MAX_APPEND_BLOB_BLOCK_COUNT = 500; +export const BLOCK_BLOB_MAX_BLOCKS: number = 50000; + +export const VERSION = "3.23.0"; +export const BLOB_API_VERSION = "2022-11-02"; +export const DATA_LAKE_API_VERSION = "2021-4-10"; +export const DEFAULT_DATA_LAKE_SERVER_HOST_NAME = "127.0.0.1"; // Change to 0.0.0.0 when needs external access +export const DEFAULT_DATA_LAKE_LISTENING_PORT = 10003; +// export const DEFAULT_CONTEXT_PATH = "azurite_dfs_context"; +//https://learn.microsoft.com/en-us/rest/api/storageservices/datalakestoragegen2/path/create +//The default permission is 0777 for a directory and 0666 for a file. The default umask is 0027. +export const DEFAULT_DIR_PERMISSIONS = "0777"; +export const DEFAULT_UMMASK = "0027"; +export const DEFAULT_FILE_PERMISSIONS = "0666"; +export const DEFAULT_OWNER = os.userInfo().username; +export const DEFAULT_GROUP = getGroup(); +export const DEFAULT_DATA_LAKE_LOKI_DB_PATH = "__azurite_db_datalake__.json"; +export const DEFAULT_DATA_LAKE_PERSISTENCE_PATH = "__datalakestorage__"; +export const DEFAULT_DATA_LAKE_EXTENT_LOKI_DB_PATH = + "__azurite_db_datalake_extent__.json"; + +export const DEFAULT_LIST_CONTAINERS_MAX_RESULTS = 5000; +export const DEFAULT_DEBUG_LOG_PATH = "./debug.log"; +export const DEFAULT_ENABLE_DEBUG_LOG = true; +export const DEFAULT_ACCESS_LOG_PATH = "./access.log"; +export const DEFAULT_ENABLE_ACCESS_LOG = true; +export const LOGGER_CONFIGS = {}; +export const DEFAULT_GC_INTERVAL_MS = 10 * 60 * 1000; +export const DEFAULT_WRITE_CONCURRENCY_PER_LOCATION = 50; +export const EMULATOR_ACCOUNT_NAME = "devstoreaccount1"; +export const EMULATOR_ACCOUNT_KEY_STR = + "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw=="; +export const EMULATOR_ACCOUNT_KEY = Buffer.from( + EMULATOR_ACCOUNT_KEY_STR, + "base64" +); + +export const EMULATOR_ACCOUNT_SKUNAME = Models.SkuName.StandardRAGRS; +export const EMULATOR_ACCOUNT_KIND = Models.AccountKind.StorageV2; + +export const HeaderConstants = { + AUTHORIZATION: "authorization", + AUTHORIZATION_SCHEME: "Bearer", + CONTENT_ENCODING: "content-encoding", + CONTENT_LANGUAGE: "content-language", + CONTENT_LENGTH: "content-length", + CONTENT_MD5: "content-md5", + CONTENT_TYPE: "content-type", + COOKIE: "Cookie", + DATE: "date", + IF_MATCH: "if-match", + IF_MODIFIED_SINCE: "if-modified-since", + IF_NONE_MATCH: "if-none-match", + IF_UNMODIFIED_SINCE: "if-unmodified-since", + SOURCE_IF_MATCH: "x-ms-source-if-match", + SOURCE_IF_MODIFIED_SINCE: "x-ms-source-if-modified-since", + SOURCE_IF_NONE_MATCH: "x-ms-source-if-none-match", + SOURCE_IF_UNMODIFIED_SINCE: "x-ms-source-if-unmodified-since", + X_MS_IF_SEQUENCE_NUMBER_LE: "x-ms-if-sequence-number-le", + X_MS_IF_SEQUENCE_NUMBER_LT: "x-ms-if-sequence-number-lt", + X_MS_IF_SEQUENCE_NUMBER_EQ: "x-ms-if-sequence-number-eq", + X_MS_BLOB_CONDITION_MAXSIZE: "x-ms-blob-condition-maxsize", + X_MS_BLOB_CONDITION_APPENDPOS: "x-ms-blob-condition-appendpos", + X_MS_SEQUENCE_NUMBER_ACTION: "x-ms-sequence-number-action", + X_MS_BLOB_SEQUENCE_NUMBER: "x-ms-blob-sequence-number", + X_MS_CONTENT_CRC64: "x-ms-content-crc64", + X_MS_RANGE_GET_CONTENT_CRC64: "x-ms-range-get-content-crc64", + X_MS_ENCRYPTION_KEY: "x-ms-encryption-key", + X_MS_ENCRYPTION_KEY_SHA256: "x-ms-encryption-key-sha256", + X_MS_ENCRYPTION_ALGORITHM: "x-ms-encryption-algorithm", + PREFIX_FOR_STORAGE: "x-ms-", + RANGE: "Range", + USER_AGENT: "User-Agent", + X_MS_CLIENT_REQUEST_ID: "x-ms-client-request-id", + X_MS_DATE: "x-ms-date", + SERVER: "Server", + X_MS_META: "x-ms-meta-", + X_MS_VERSION: "x-ms-version", + ORIGIN: "origin", + VARY: "Vary", + ACCESS_CONTROL_EXPOSE_HEADERS: "Access-Control-Expose-Headers", + ACCESS_CONTROL_ALLOW_ORIGIN: "Access-Control-Allow-Origin", + ACCESS_CONTROL_ALLOW_CREDENTIALS: "Access-Control-Allow-Credentials", + ACCESS_CONTROL_ALLOW_METHODS: "Access-Control-Allow-Methods", + ACCESS_CONTROL_ALLOW_HEADERS: "Access-Control-Allow-Headers", + ACCESS_CONTROL_MAX_AGE: "Access-Control-Max-Age", + ACCESS_CONTROL_REQUEST_METHOD: "access-control-request-method", + ACCESS_CONTROL_REQUEST_HEADERS: "access-control-request-headers" +}; + +export const MethodConstants = { + OPTIONS: "OPTIONS" +}; + +export const SECONDARY_SUFFIX = "-secondary"; + +export const DEFAULT_DATA_LAKE_PERSISTENCE_ARRAY: StoreDestinationArray = [ + { + locationId: "Default", + locationPath: DEFAULT_DATA_LAKE_PERSISTENCE_PATH, + maxConcurrency: DEFAULT_WRITE_CONCURRENCY_PER_LOCATION + } +]; + +export const ValidAPIVersions = [ + "2022-11-02", + "2021-12-02", + "2021-10-04", + "2021-08-06", + "2021-06-08", + "2021-04-10", + "2021-02-12", + "2020-12-06", + "2020-10-02", + "2020-08-04", + "2020-06-12", + "2020-04-08", + "2020-02-10", + "2019-12-12", + "2019-10-10", + "2019-07-07", + "2019-02-02", + "2018-11-09", + "2018-03-28", + "2017-11-09", + "2017-07-29", + "2017-04-17", + "2016-05-31", + "2015-12-11", + "2015-07-08", + "2015-04-05", + "2015-02-21", + "2014-02-14", + "2013-08-15", + "2012-02-12", + "2011-08-18", + "2009-09-19", + "2009-07-17", + "2009-04-14" +]; + +// Validate audience, accept following audience patterns +// https://storage.azure.com +// https://storage.azure.com/ +// e406a681-f3d4-42a8-90b6-c2b029497af1 +// https://*.blob.core.windows.net +// https://*.blob.core.windows.net/ +// https://*.blob.core.chinacloudapi.cn +// https://*.blob.core.chinacloudapi.cn/ +// https://*.blob.core.usgovcloudapi.net +// https://*.blob.core.usgovcloudapi.net/ +// https://*.blob.core.cloudapi.de +// https://*.blob.core.cloudapi.de/ +// https://*.dfs.core.windows.net +// https://*.dfs.core.windows.net/ +// https://*.dfs.core.chinacloudapi.cn +// https://*.dfs.core.chinacloudapi.cn/ +// https://*.dfs.core.usgovcloudapi.net +// https://*.dfs.core.usgovcloudapi.net/ +// https://*.dfs.core.cloudapi.de +// https://*.dfs.core.cloudapi.de/ +export const VALID_DATALAKE_AUDIENCES = [ + /^https:\/\/storage\.azure\.com[\/]?$/, + /^e406a681-f3d4-42a8-90b6-c2b029497af1$/, + /^https:\/\/(.*)\.blob\.core\.windows\.net[\/]?$/, + /^https:\/\/(.*)\.blob\.core\.chinacloudapi\.cn[\/]?$/, + /^https:\/\/(.*)\.blob\.core\.usgovcloudapi\.net[\/]?$/, + /^https:\/\/(.*)\.blob\.core\.cloudapi\.de[\/]?$/, + /^https:\/\/(.*)\.dfs\.core\.windows\.net[\/]?$/, + /^https:\/\/(.*)\.dfs\.core\.chinacloudapi\.cn[\/]?$/, + /^https:\/\/(.*)\.dfs\.core\.usgovcloudapi\.net[\/]?$/, + /^https:\/\/(.*)\.dfs\.core\.cloudapi\.de[\/]?$/ +]; + +export const HTTP_LINE_ENDING = "\r\n"; +export const HTTP_HEADER_DELIMITER = ": "; + +export const USERDELEGATIONKEY_BASIC_KEY = + "I17GKLvcJUossaebtsEDZZ2RJ8GNLwLH4m7hRMxbVbkx6wNIRAABj4Rtw0FBhFuEAgmbL4gFMzUw+AStz9Sqdg=="; + +export const AUTHENTICATION_BEARERTOKEN_REQUIRED = + "Only authentication scheme Bearer is supported"; + +function getGroup(): string { + if (os.platform() === "win32") return ""; + const options: ExecSyncOptionsWithStringEncoding = { + encoding: "utf8" + }; + const output = execSync("id -gn", options); + if (output) { + return output.substring(0, output.length - 1); //remove trailing \n + } + + return ""; +} \ No newline at end of file diff --git a/src/dfs/utils/operationsMapper.ts b/src/dfs/utils/operationsMapper.ts new file mode 100644 index 000000000..e362f7e91 --- /dev/null +++ b/src/dfs/utils/operationsMapper.ts @@ -0,0 +1,628 @@ +import Operation from "../generated/artifacts/operation"; +import BlobOperation from "../../blob/generated/artifacts/operation"; + +export function operationBlobToDfs( + operation: BlobOperation +): Operation | undefined { + return blobOperationToDfsOpeation.get(operation); +} + +export function operationDfsToBlob( + operation: Operation +): BlobOperation | undefined { + return DfsOperationToBlobOpeation.get(operation); +} + +const blobOperationToDfsOpeation = new Map(); + +//Service +blobOperationToDfsOpeation.set( + BlobOperation.Service_SetProperties, + Operation.Service_SetProperties +); +blobOperationToDfsOpeation.set( + BlobOperation.Service_GetProperties, + Operation.Service_GetProperties +); +blobOperationToDfsOpeation.set( + BlobOperation.Service_GetStatistics, + Operation.Service_GetStatistics +); +blobOperationToDfsOpeation.set( + BlobOperation.Service_ListContainersSegment, + Operation.Service_ListContainersSegment +); +blobOperationToDfsOpeation.set( + BlobOperation.Service_GetUserDelegationKey, + Operation.Service_GetUserDelegationKey +); +blobOperationToDfsOpeation.set( + BlobOperation.Service_GetAccountInfo, + Operation.Service_GetAccountInfo +); +blobOperationToDfsOpeation.set( + BlobOperation.Service_GetAccountInfoWithHead, + Operation.Service_GetAccountInfoWithHead +); +blobOperationToDfsOpeation.set( + BlobOperation.Service_SubmitBatch, + Operation.Service_SubmitBatch +); +blobOperationToDfsOpeation.set( + BlobOperation.Service_FilterBlobs, + Operation.Service_FilterBlobs +); +//Container +blobOperationToDfsOpeation.set( + BlobOperation.Container_Create, + Operation.Container_Create +); +blobOperationToDfsOpeation.set( + BlobOperation.Container_GetProperties, + Operation.Container_GetProperties +); +blobOperationToDfsOpeation.set( + BlobOperation.Container_GetPropertiesWithHead, + Operation.Container_GetPropertiesWithHead +); +blobOperationToDfsOpeation.set( + BlobOperation.Container_Delete, + Operation.Container_Delete +); +blobOperationToDfsOpeation.set( + BlobOperation.Container_SetMetadata, + Operation.Container_SetMetadata +); +blobOperationToDfsOpeation.set( + BlobOperation.Container_GetAccessPolicy, + Operation.Container_GetAccessPolicy +); +blobOperationToDfsOpeation.set( + BlobOperation.Container_SetAccessPolicy, + Operation.Container_SetAccessPolicy +); +blobOperationToDfsOpeation.set( + BlobOperation.Container_Restore, + Operation.Container_Restore +); +blobOperationToDfsOpeation.set( + BlobOperation.Container_SubmitBatch, + Operation.Container_SubmitBatch +); +blobOperationToDfsOpeation.set( + BlobOperation.Container_FilterBlobs, + Operation.Container_FilterBlobs +); +blobOperationToDfsOpeation.set( + BlobOperation.Container_AcquireLease, + Operation.Container_AcquireLease +); +blobOperationToDfsOpeation.set( + BlobOperation.Container_ReleaseLease, + Operation.Container_ReleaseLease +); +blobOperationToDfsOpeation.set( + BlobOperation.Container_RenewLease, + Operation.Container_RenewLease +); +blobOperationToDfsOpeation.set( + BlobOperation.Container_BreakLease, + Operation.Container_BreakLease +); +blobOperationToDfsOpeation.set( + BlobOperation.Container_ChangeLease, + Operation.Container_ChangeLease +); +blobOperationToDfsOpeation.set( + BlobOperation.Container_ListBlobFlatSegment, + Operation.FileSystem_ListBlobFlatSegment +); +blobOperationToDfsOpeation.set( + BlobOperation.Container_ListBlobHierarchySegment, + Operation.FileSystem_ListBlobHierarchySegment +); +blobOperationToDfsOpeation.set( + BlobOperation.Container_GetAccountInfo, + Operation.Container_GetAccountInfo +); +blobOperationToDfsOpeation.set( + BlobOperation.Container_GetAccountInfoWithHead, + Operation.Container_GetAccountInfoWithHead +); +//Blob +blobOperationToDfsOpeation.set( + BlobOperation.Blob_Download, + Operation.Path_Read +); +blobOperationToDfsOpeation.set( + BlobOperation.Blob_GetProperties, + Operation.Path_GetProperties +); +blobOperationToDfsOpeation.set( + BlobOperation.Blob_Delete, + Operation.Path_Delete +); +blobOperationToDfsOpeation.set( + BlobOperation.Blob_Undelete, + Operation.Blob_Undelete +); +blobOperationToDfsOpeation.set( + BlobOperation.Blob_SetExpiry, + Operation.Blob_SetExpiry +); +blobOperationToDfsOpeation.set( + BlobOperation.Blob_SetHTTPHeaders, + Operation.Blob_SetHTTPHeaders +); +blobOperationToDfsOpeation.set( + BlobOperation.Blob_SetImmutabilityPolicy, + Operation.Blob_SetImmutabilityPolicy +); +blobOperationToDfsOpeation.set( + BlobOperation.Blob_DeleteImmutabilityPolicy, + Operation.Blob_DeleteImmutabilityPolicy +); +blobOperationToDfsOpeation.set( + BlobOperation.Blob_SetLegalHold, + Operation.Blob_SetLegalHold +); +blobOperationToDfsOpeation.set( + BlobOperation.Blob_SetMetadata, + Operation.Blob_SetMetadata +); +blobOperationToDfsOpeation.set( + BlobOperation.Blob_AcquireLease, + Operation.Blob_AcquireLease +); +blobOperationToDfsOpeation.set( + BlobOperation.Blob_ReleaseLease, + Operation.Blob_ReleaseLease +); +blobOperationToDfsOpeation.set( + BlobOperation.Blob_RenewLease, + Operation.Blob_RenewLease +); +blobOperationToDfsOpeation.set( + BlobOperation.Blob_ChangeLease, + Operation.Blob_ChangeLease +); +blobOperationToDfsOpeation.set( + BlobOperation.Blob_BreakLease, + Operation.Blob_BreakLease +); +blobOperationToDfsOpeation.set( + BlobOperation.Blob_CreateSnapshot, + Operation.Blob_CreateSnapshot +); +blobOperationToDfsOpeation.set( + BlobOperation.Blob_StartCopyFromURL, + Operation.Blob_StartCopyFromURL +); +blobOperationToDfsOpeation.set( + BlobOperation.Blob_CopyFromURL, + Operation.Blob_CopyFromURL +); +blobOperationToDfsOpeation.set( + BlobOperation.Blob_AbortCopyFromURL, + Operation.Blob_AbortCopyFromURL +); +blobOperationToDfsOpeation.set( + BlobOperation.Blob_SetTier, + Operation.Blob_SetTier +); +blobOperationToDfsOpeation.set( + BlobOperation.Blob_GetAccountInfo, + Operation.Blob_GetAccountInfo +); +blobOperationToDfsOpeation.set( + BlobOperation.Blob_GetAccountInfoWithHead, + Operation.Blob_GetAccountInfoWithHead +); +blobOperationToDfsOpeation.set(BlobOperation.Blob_Query, Operation.Blob_Query); +blobOperationToDfsOpeation.set( + BlobOperation.Blob_GetTags, + Operation.Blob_GetTags +); +blobOperationToDfsOpeation.set( + BlobOperation.Blob_SetTags, + Operation.Blob_SetTags +); +//PageBlob +blobOperationToDfsOpeation.set( + BlobOperation.PageBlob_Create, + Operation.PageBlob_Create +); +blobOperationToDfsOpeation.set( + BlobOperation.PageBlob_UploadPages, + Operation.PageBlob_UploadPages +); +blobOperationToDfsOpeation.set( + BlobOperation.PageBlob_ClearPages, + Operation.PageBlob_ClearPages +); +blobOperationToDfsOpeation.set( + BlobOperation.PageBlob_UploadPagesFromURL, + Operation.PageBlob_UploadPagesFromURL +); +blobOperationToDfsOpeation.set( + BlobOperation.PageBlob_GetPageRanges, + Operation.PageBlob_GetPageRanges +); +blobOperationToDfsOpeation.set( + BlobOperation.PageBlob_GetPageRangesDiff, + Operation.PageBlob_GetPageRangesDiff +); +blobOperationToDfsOpeation.set( + BlobOperation.PageBlob_Resize, + Operation.PageBlob_Resize +); +blobOperationToDfsOpeation.set( + BlobOperation.PageBlob_UpdateSequenceNumber, + Operation.PageBlob_UpdateSequenceNumber +); +blobOperationToDfsOpeation.set( + BlobOperation.PageBlob_CopyIncremental, + Operation.PageBlob_CopyIncremental +); +//AppendBlob +blobOperationToDfsOpeation.set( + BlobOperation.AppendBlob_Create, + Operation.AppendBlob_Create +); +blobOperationToDfsOpeation.set( + BlobOperation.AppendBlob_AppendBlock, + Operation.AppendBlob_AppendBlock +); +blobOperationToDfsOpeation.set( + BlobOperation.AppendBlob_AppendBlockFromUrl, + Operation.AppendBlob_AppendBlockFromUrl +); +blobOperationToDfsOpeation.set( + BlobOperation.AppendBlob_Seal, + Operation.AppendBlob_Seal +); +//BlokcBlob +blobOperationToDfsOpeation.set( + BlobOperation.BlockBlob_Upload, + Operation.BlockBlob_Upload +); +blobOperationToDfsOpeation.set( + BlobOperation.BlockBlob_PutBlobFromUrl, + Operation.BlockBlob_PutBlobFromUrl +); +blobOperationToDfsOpeation.set( + BlobOperation.BlockBlob_StageBlock, + Operation.BlockBlob_StageBlock +); +blobOperationToDfsOpeation.set( + BlobOperation.BlockBlob_StageBlockFromURL, + Operation.BlockBlob_StageBlockFromURL +); +blobOperationToDfsOpeation.set( + BlobOperation.BlockBlob_CommitBlockList, + Operation.BlockBlob_CommitBlockList +); +blobOperationToDfsOpeation.set( + BlobOperation.BlockBlob_GetBlockList, + Operation.BlockBlob_GetBlockList +); + +const DfsOperationToBlobOpeation = new Map< + Operation, + BlobOperation | undefined +>(); + +//Service +DfsOperationToBlobOpeation.set(Operation.Service_ListFileSystems, undefined); +DfsOperationToBlobOpeation.set( + Operation.Service_SetProperties, + BlobOperation.Service_SetProperties +); +DfsOperationToBlobOpeation.set( + Operation.Service_GetProperties, + BlobOperation.Service_GetProperties +); +DfsOperationToBlobOpeation.set( + Operation.Service_GetStatistics, + BlobOperation.Service_GetStatistics +); +DfsOperationToBlobOpeation.set( + Operation.Service_ListContainersSegment, + BlobOperation.Service_ListContainersSegment +); +DfsOperationToBlobOpeation.set( + Operation.Service_GetUserDelegationKey, + BlobOperation.Service_GetUserDelegationKey +); +DfsOperationToBlobOpeation.set( + Operation.Service_GetAccountInfo, + BlobOperation.Service_GetAccountInfo +); +DfsOperationToBlobOpeation.set( + Operation.Service_GetAccountInfoWithHead, + BlobOperation.Service_GetAccountInfoWithHead +); +DfsOperationToBlobOpeation.set( + Operation.Service_SubmitBatch, + BlobOperation.Service_SubmitBatch +); +DfsOperationToBlobOpeation.set( + Operation.Service_FilterBlobs, + BlobOperation.Service_FilterBlobs +); +//Filesystem +DfsOperationToBlobOpeation.set(Operation.FileSystem_Create, undefined); +DfsOperationToBlobOpeation.set(Operation.FileSystem_SetProperties, undefined); +DfsOperationToBlobOpeation.set(Operation.FileSystem_GetProperties, undefined); +DfsOperationToBlobOpeation.set(Operation.FileSystem_Delete, undefined); +DfsOperationToBlobOpeation.set(Operation.FileSystem_ListPaths, undefined); +DfsOperationToBlobOpeation.set( + Operation.FileSystem_ListBlobFlatSegment, + BlobOperation.Container_ListBlobFlatSegment +); +DfsOperationToBlobOpeation.set( + Operation.FileSystem_ListBlobHierarchySegment, + BlobOperation.Container_ListBlobHierarchySegment +); +//Path +DfsOperationToBlobOpeation.set(Operation.Path_Create, undefined); +DfsOperationToBlobOpeation.set(Operation.Path_Update, undefined); +DfsOperationToBlobOpeation.set(Operation.Path_Lease, undefined); +DfsOperationToBlobOpeation.set( + Operation.Path_Read, + BlobOperation.Blob_Download +); +DfsOperationToBlobOpeation.set(Operation.Path_GetProperties, undefined); +DfsOperationToBlobOpeation.set( + Operation.Path_Delete, + BlobOperation.Blob_Delete +); +DfsOperationToBlobOpeation.set(Operation.Path_SetAccessControl, undefined); +DfsOperationToBlobOpeation.set( + Operation.Path_SetAccessControlRecursive, + undefined +); +DfsOperationToBlobOpeation.set(Operation.Path_SetProperties, undefined); +DfsOperationToBlobOpeation.set(Operation.Path_FlushData, undefined); +DfsOperationToBlobOpeation.set(Operation.Path_AppendData, undefined); +DfsOperationToBlobOpeation.set( + Operation.Path_SetExpiry, + BlobOperation.Blob_SetExpiry +); +DfsOperationToBlobOpeation.set( + Operation.Path_Undelete, + BlobOperation.Blob_Undelete +); +//Container +DfsOperationToBlobOpeation.set( + Operation.Container_Create, + BlobOperation.Container_Create +); +DfsOperationToBlobOpeation.set( + Operation.Container_GetProperties, + BlobOperation.Container_GetProperties +); +DfsOperationToBlobOpeation.set( + Operation.Container_GetPropertiesWithHead, + BlobOperation.Container_GetPropertiesWithHead +); +DfsOperationToBlobOpeation.set( + Operation.Container_Delete, + BlobOperation.Container_Delete +); +DfsOperationToBlobOpeation.set( + Operation.Container_SetMetadata, + BlobOperation.Container_SetMetadata +); +DfsOperationToBlobOpeation.set( + Operation.Container_GetAccessPolicy, + BlobOperation.Container_GetAccessPolicy +); +DfsOperationToBlobOpeation.set( + Operation.Container_SetAccessPolicy, + BlobOperation.Container_SetAccessPolicy +); +DfsOperationToBlobOpeation.set( + Operation.Container_Restore, + BlobOperation.Container_Restore +); +DfsOperationToBlobOpeation.set( + Operation.Container_SubmitBatch, + BlobOperation.Container_SubmitBatch +); +DfsOperationToBlobOpeation.set( + Operation.Container_FilterBlobs, + BlobOperation.Container_FilterBlobs +); +DfsOperationToBlobOpeation.set( + Operation.Container_AcquireLease, + BlobOperation.Container_AcquireLease +); +DfsOperationToBlobOpeation.set( + Operation.Container_ReleaseLease, + BlobOperation.Container_ReleaseLease +); +DfsOperationToBlobOpeation.set( + Operation.Container_RenewLease, + BlobOperation.Container_RenewLease +); +DfsOperationToBlobOpeation.set( + Operation.Container_BreakLease, + BlobOperation.Container_BreakLease +); +DfsOperationToBlobOpeation.set( + Operation.Container_ChangeLease, + BlobOperation.Container_ChangeLease +); +DfsOperationToBlobOpeation.set( + Operation.Container_GetAccountInfo, + BlobOperation.Container_GetAccountInfo +); +DfsOperationToBlobOpeation.set( + Operation.Container_GetAccountInfoWithHead, + BlobOperation.Container_GetAccountInfoWithHead +); +//PageBlob +DfsOperationToBlobOpeation.set( + Operation.PageBlob_Create, + BlobOperation.PageBlob_Create +); +DfsOperationToBlobOpeation.set( + Operation.PageBlob_UploadPages, + BlobOperation.PageBlob_UploadPages +); +DfsOperationToBlobOpeation.set( + Operation.PageBlob_ClearPages, + BlobOperation.PageBlob_ClearPages +); +DfsOperationToBlobOpeation.set( + Operation.PageBlob_UploadPagesFromURL, + BlobOperation.PageBlob_UploadPagesFromURL +); +DfsOperationToBlobOpeation.set( + Operation.PageBlob_GetPageRanges, + BlobOperation.PageBlob_GetPageRanges +); +DfsOperationToBlobOpeation.set( + Operation.PageBlob_GetPageRangesDiff, + BlobOperation.PageBlob_GetPageRangesDiff +); +DfsOperationToBlobOpeation.set( + Operation.PageBlob_Resize, + BlobOperation.PageBlob_Resize +); +DfsOperationToBlobOpeation.set( + Operation.PageBlob_UpdateSequenceNumber, + BlobOperation.PageBlob_UpdateSequenceNumber +); +DfsOperationToBlobOpeation.set( + Operation.PageBlob_CopyIncremental, + BlobOperation.PageBlob_CopyIncremental +); +//AppendBlob +DfsOperationToBlobOpeation.set( + Operation.AppendBlob_Create, + BlobOperation.AppendBlob_Create +); +DfsOperationToBlobOpeation.set( + Operation.AppendBlob_AppendBlock, + BlobOperation.AppendBlob_AppendBlock +); +DfsOperationToBlobOpeation.set( + Operation.AppendBlob_AppendBlockFromUrl, + BlobOperation.AppendBlob_AppendBlockFromUrl +); +DfsOperationToBlobOpeation.set( + Operation.AppendBlob_Seal, + BlobOperation.AppendBlob_Seal +); +//BlockBlob +DfsOperationToBlobOpeation.set( + Operation.BlockBlob_Upload, + BlobOperation.BlockBlob_Upload +); +DfsOperationToBlobOpeation.set( + Operation.BlockBlob_PutBlobFromUrl, + BlobOperation.BlockBlob_PutBlobFromUrl +); +DfsOperationToBlobOpeation.set( + Operation.BlockBlob_StageBlock, + BlobOperation.BlockBlob_StageBlock +); +DfsOperationToBlobOpeation.set( + Operation.BlockBlob_StageBlockFromURL, + BlobOperation.BlockBlob_StageBlockFromURL +); +DfsOperationToBlobOpeation.set( + Operation.BlockBlob_CommitBlockList, + BlobOperation.BlockBlob_CommitBlockList +); +DfsOperationToBlobOpeation.set( + Operation.BlockBlob_GetBlockList, + BlobOperation.BlockBlob_GetBlockList +); +DfsOperationToBlobOpeation.set( + Operation.Blob_Undelete, + BlobOperation.Blob_Undelete +); +DfsOperationToBlobOpeation.set( + Operation.Blob_SetExpiry, + BlobOperation.Blob_SetExpiry +); +DfsOperationToBlobOpeation.set( + Operation.Blob_SetHTTPHeaders, + BlobOperation.Blob_SetHTTPHeaders +); +DfsOperationToBlobOpeation.set( + Operation.Blob_SetImmutabilityPolicy, + BlobOperation.Blob_SetImmutabilityPolicy +); +DfsOperationToBlobOpeation.set( + Operation.Blob_DeleteImmutabilityPolicy, + BlobOperation.Blob_DeleteImmutabilityPolicy +); +DfsOperationToBlobOpeation.set( + Operation.Blob_SetLegalHold, + BlobOperation.Blob_SetLegalHold +); +DfsOperationToBlobOpeation.set( + Operation.Blob_SetMetadata, + BlobOperation.Blob_SetMetadata +); +DfsOperationToBlobOpeation.set( + Operation.Blob_AcquireLease, + BlobOperation.Blob_AcquireLease +); +DfsOperationToBlobOpeation.set( + Operation.Blob_ReleaseLease, + BlobOperation.Blob_ReleaseLease +); +DfsOperationToBlobOpeation.set( + Operation.Blob_RenewLease, + BlobOperation.Blob_RenewLease +); +DfsOperationToBlobOpeation.set( + Operation.Blob_ChangeLease, + BlobOperation.Blob_ChangeLease +); +DfsOperationToBlobOpeation.set( + Operation.Blob_BreakLease, + BlobOperation.Blob_BreakLease +); +DfsOperationToBlobOpeation.set( + Operation.Blob_CreateSnapshot, + BlobOperation.Blob_CreateSnapshot +); +DfsOperationToBlobOpeation.set( + Operation.Blob_StartCopyFromURL, + BlobOperation.Blob_StartCopyFromURL +); +DfsOperationToBlobOpeation.set( + Operation.Blob_CopyFromURL, + BlobOperation.Blob_CopyFromURL +); +DfsOperationToBlobOpeation.set( + Operation.Blob_AbortCopyFromURL, + BlobOperation.Blob_AbortCopyFromURL +); +DfsOperationToBlobOpeation.set( + Operation.Blob_SetTier, + BlobOperation.Blob_SetTier +); +DfsOperationToBlobOpeation.set( + Operation.Blob_GetAccountInfo, + BlobOperation.Blob_GetAccountInfo +); +DfsOperationToBlobOpeation.set( + Operation.Blob_GetAccountInfoWithHead, + BlobOperation.Blob_GetAccountInfoWithHead +); +DfsOperationToBlobOpeation.set(Operation.Blob_Query, BlobOperation.Blob_Query); +DfsOperationToBlobOpeation.set( + Operation.Blob_GetTags, + BlobOperation.Blob_GetTags +); +DfsOperationToBlobOpeation.set( + Operation.Blob_SetTags, + BlobOperation.Blob_SetTags +); diff --git a/src/dfs/utils/utils.ts b/src/dfs/utils/utils.ts new file mode 100644 index 000000000..3570cb18e --- /dev/null +++ b/src/dfs/utils/utils.ts @@ -0,0 +1,90 @@ +import { createHmac } from "crypto"; + +import StorageErrorFactory from "../errors/StorageErrorFactory"; +import Operation from "../generated/artifacts/operation"; +import Context from "../../blob/generated/Context"; +import { USERDELEGATIONKEY_BASIC_KEY } from "./constants"; +import IRequest from "../../blob/generated/IRequest"; + +export function checkApiVersion( + inputApiVersion: string, + validApiVersions: Array, + context: Context +): void { + if (!validApiVersions.includes(inputApiVersion)) { + throw StorageErrorFactory.getInvalidAPIVersion(context, inputApiVersion); + } +} + +export function validateContainerName(context: Context, containerName: string) { + if ( + containerName !== "" && + (containerName!.length < 3 || containerName!.length > 63) + ) { + throw StorageErrorFactory.getOutOfRangeName(context); + } + const reg = new RegExp("^[a-z0-9](?!.*--)[a-z0-9-]{1,61}[a-z0-9]$"); + if (!reg.test(containerName!)) { + throw StorageErrorFactory.getInvalidResourceName(context); + } +} + +export function getUserDelegationKeyValue( + signedObjectid: string, + signedTenantid: string, + signedStartsOn: string, + signedExpiresOn: string, + signedVersion: string +): string { + const stringToSign = [ + signedObjectid, + signedTenantid, + signedStartsOn, + signedExpiresOn, + "b", + signedVersion + ].join("\n"); + + return createHmac("sha256", USERDELEGATIONKEY_BASIC_KEY) + .update(stringToSign, "utf8") + .digest("base64"); +} + +const DATA_LAKE_OPERATIONS = [ + Operation.FileSystem_Create, + Operation.FileSystem_SetProperties, + Operation.FileSystem_GetProperties, + Operation.FileSystem_Delete, + Operation.FileSystem_ListPaths, + Operation.Path_Create, + Operation.Path_Update, + Operation.Path_Lease, + Operation.Path_Delete, + Operation.Path_SetAccessControl, + Operation.Path_SetAccessControlRecursive, + Operation.Path_FlushData, + Operation.Path_AppendData, + Operation.Path_SetExpiry, + Operation.Path_Undelete +]; + +const COMMON_OPERATIONS = [Operation.Path_Read, Operation.Path_GetProperties]; + +export function isDataLakeOperation( + context: Context, + request: IRequest | undefined = context.request +): boolean { + const accept = request?.getHeader("Accept"); + return ( + DATA_LAKE_OPERATIONS.includes(context.context.dfsOperation!) || + (COMMON_OPERATIONS.includes(context.context.dfsOperation!) && + accept !== undefined && + accept.includes("json")) + ); +} + +export function removeSlash(path: string): string { + if (!path.endsWith("/")) return path; + + return path.substring(0, path.length - 1); +} diff --git a/src/extension.ts b/src/extension.ts index 84bf64b26..2e2a847b2 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -4,6 +4,7 @@ import VSCAccessLog from "./common/VSCAccessLog"; import VSCNotification from "./common/VSCNotification"; import VSCProgress from "./common/VSCProgress"; import VSCServerManagerBlob from "./common/VSCServerManagerBlob"; +import VSCServerManagerDataLake from "./common/VSCServerManagerDataLake"; import VSCServerManagerQueue from "./common/VSCServerManagerQueue"; import VSCServerManagerTable from "./common/VSCServerManagerTable"; import VSCStatusBarItem from "./common/VSCStatusBarItem"; @@ -11,6 +12,7 @@ import VSCStatusBarItem from "./common/VSCStatusBarItem"; export function activate(context: ExtensionContext) { // Initialize server managers const blobServerManager = new VSCServerManagerBlob(); + const dataLakeServerManager = new VSCServerManagerDataLake(); const queueServerManager = new VSCServerManagerQueue(); const tableServerManager = new VSCServerManagerTable(); @@ -27,21 +29,28 @@ export function activate(context: ExtensionContext) { tableServerManager, window.createStatusBarItem(StatusBarAlignment.Right, 1002) ); + const vscDataLakeStatusBar = new VSCStatusBarItem( + dataLakeServerManager, + window.createStatusBarItem(StatusBarAlignment.Right, 1003) + ); blobServerManager.addEventListener(vscBlobStatusBar); queueServerManager.addEventListener(vscQueueStatusBar); tableServerManager.addEventListener(vscTableStatusBar); + dataLakeServerManager.addEventListener(vscDataLakeStatusBar); // Hook up notification handlers const notification = new VSCNotification(); blobServerManager.addEventListener(notification); queueServerManager.addEventListener(notification); tableServerManager.addEventListener(notification); + dataLakeServerManager.addEventListener(notification); // Hook up progress handlers blobServerManager.addEventListener(new VSCProgress()); queueServerManager.addEventListener(new VSCProgress()); tableServerManager.addEventListener(new VSCProgress()); + dataLakeServerManager.addEventListener(new VSCProgress()); // Hook up access log handlers blobServerManager.addEventListener( @@ -53,22 +62,28 @@ export function activate(context: ExtensionContext) { tableServerManager.addEventListener( new VSCAccessLog(tableServerManager.accessChannelStream) ); + dataLakeServerManager.addEventListener( + new VSCAccessLog(dataLakeServerManager.accessChannelStream) + ); context.subscriptions.push( commands.registerCommand("azurite.start", () => { blobServerManager.start(); queueServerManager.start(); tableServerManager.start(); + dataLakeServerManager.start(); }), commands.registerCommand("azurite.close", () => { blobServerManager.close(); queueServerManager.close(); tableServerManager.close(); + dataLakeServerManager.close(); }), commands.registerCommand("azurite.clean", () => { blobServerManager.clean(); queueServerManager.clean(); tableServerManager.clean(); + dataLakeServerManager.clean(); }), commands.registerCommand(blobServerManager.getStartCommand(), async () => { @@ -101,9 +116,23 @@ export function activate(context: ExtensionContext) { tableServerManager.clean(); }), + commands.registerCommand( + dataLakeServerManager.getStartCommand(), + async () => { + await dataLakeServerManager.start(); + } + ), + commands.registerCommand(dataLakeServerManager.getCloseCommand(), () => { + dataLakeServerManager.close(); + }), + commands.registerCommand(dataLakeServerManager.getCleanCommand(), () => { + dataLakeServerManager.clean(); + }), + vscBlobStatusBar.statusBarItem, vscQueueStatusBar.statusBarItem, - vscTableStatusBar.statusBarItem + vscTableStatusBar.statusBarItem, + vscDataLakeStatusBar.statusBarItem ); } diff --git a/swagger/blob-storage-2021-10-04-data-lake.json b/swagger/blob-storage-2021-10-04-data-lake.json new file mode 100644 index 000000000..25ebaf156 --- /dev/null +++ b/swagger/blob-storage-2021-10-04-data-lake.json @@ -0,0 +1,10651 @@ +{ + "swagger": "2.0", + "info": { + "title": "Azure Blob Storage", + "version": "2021-10-04", + "x-ms-code-generation-settings": { + "header": "MIT", + "strictSpecAdherence": false + } + }, + "x-ms-parameterized-host": { + "hostTemplate": "{url}", + "useSchemePrefix": false, + "positionInOperation": "first", + "parameters": [ + { + "$ref": "#/parameters/Url" + } + ] + }, + "schemes": [ + "https" + ], + "consumes": [ + "application/xml" + ], + "produces": [ + "application/xml" + ], + "paths": {}, + "x-ms-paths": { + "/?restype=service&comp=properties": { + "put": { + "tags": [ + "service" + ], + "operationId": "Service_SetProperties", + "description": "Sets properties for a storage account's Blob service endpoint, including properties for Storage Analytics and CORS (Cross-Origin Resource Sharing) rules", + "parameters": [ + { + "$ref": "#/parameters/StorageServiceProperties" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "202": { + "description": "Success (Accepted)", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "get": { + "tags": [ + "service" + ], + "operationId": "Service_GetProperties", + "description": "gets the properties of a storage account's Blob service, including properties for Storage Analytics and CORS (Cross-Origin Resource Sharing) rules.", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "Success.", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + } + }, + "schema": { + "$ref": "#/definitions/StorageServiceProperties" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "restype", + "description": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "service" + ] + }, + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "properties" + ] + } + ] + }, + "/?restype=service&comp=stats": { + "get": { + "tags": [ + "service" + ], + "operationId": "Service_GetStatistics", + "description": "Retrieves statistics related to replication for the Blob service. It is only available on the secondary location endpoint when read-access geo-redundant replication is enabled for the storage account.", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "Success.", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + }, + "schema": { + "$ref": "#/definitions/StorageServiceStats" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "restype", + "description": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "service" + ] + }, + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "stats" + ] + } + ] + }, + "/?comp=list": { + "get": { + "tags": [ + "service" + ], + "operationId": "Service_ListContainersSegment", + "description": "The List Containers Segment operation returns a list of the containers under the specified account", + "parameters": [ + { + "$ref": "#/parameters/Prefix" + }, + { + "$ref": "#/parameters/Marker" + }, + { + "$ref": "#/parameters/MaxResultsBlob" + }, + { + "$ref": "#/parameters/ListContainersInclude" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "Success.", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + } + }, + "schema": { + "$ref": "#/definitions/ListContainersSegmentResponse" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "NextMarker" + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "list" + ] + } + ] + }, + "/?restype=service&comp=userdelegationkey": { + "post": { + "tags": [ + "service" + ], + "operationId": "Service_GetUserDelegationKey", + "description": "Retrieves a user delegation key for the Blob service. This is only a valid operation when using bearer token authentication.", + "parameters": [ + { + "$ref": "#/parameters/KeyInfo" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "Success.", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + }, + "schema": { + "$ref": "#/definitions/UserDelegationKey" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "restype", + "description": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "service" + ] + }, + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "userdelegationkey" + ] + } + ] + }, + "/?restype=account&comp=properties": { + "get": { + "tags": [ + "service" + ], + "operationId": "Service_GetAccountInfo", + "description": "Returns the sku name and account kind ", + "parameters": [ + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Success (OK)", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-sku-name": { + "x-ms-client-name": "SkuName", + "type": "string", + "enum": [ + "Standard_LRS", + "Standard_GRS", + "Standard_RAGRS", + "Standard_ZRS", + "Premium_LRS" + ], + "x-ms-enum": { + "name": "SkuName", + "modelAsString": false + }, + "description": "Identifies the sku name of the account" + }, + "x-ms-account-kind": { + "x-ms-client-name": "AccountKind", + "type": "string", + "enum": [ + "Storage", + "BlobStorage", + "StorageV2", + "FileStorage", + "BlockBlobStorage" + ], + "x-ms-enum": { + "name": "AccountKind", + "modelAsString": false + }, + "description": "Identifies the account kind" + }, + "x-ms-is-hns-enabled": { + "x-ms-client-name": "IsHierarchicalNamespaceEnabled", + "type": "boolean", + "description": "Version 2019-07-07 and newer. Indicates if the account has a hierarchical namespace enabled." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "head": { + "tags": ["service"], + "operationId": "Service_GetAccountInfoWithHead", + "description": "Returns the sku name and account kind ", + "parameters": [ + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Success (OK)", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-sku-name": { + "x-ms-client-name": "SkuName", + "type": "string", + "enum": [ + "Standard_LRS", + "Standard_GRS", + "Standard_RAGRS", + "Standard_ZRS", + "Premium_LRS" + ], + "x-ms-enum": { + "name": "SkuName", + "modelAsString": false + }, + "description": "Identifies the sku name of the account" + }, + "x-ms-account-kind": { + "x-ms-client-name": "AccountKind", + "type": "string", + "enum": [ + "Storage", + "BlobStorage", + "StorageV2", + "FileStorage", + "BlockBlobStorage" + ], + "x-ms-enum": { + "name": "AccountKind", + "modelAsString": false + }, + "description": "Identifies the account kind" + }, + "x-ms-is-hns-enabled": { + "x-ms-client-name": "IsHierarchicalNamespaceEnabled", + "type": "boolean", + "description": "Version 2019-07-07 and newer. Indicates if the account has a hierarchical namespace enabled." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "restype", + "description": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": ["account"] + }, + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["properties"] + } + ] + }, + "/?comp=batch": { + "post": { + "tags": ["service"], + "operationId": "Service_SubmitBatch", + "description": "The Batch operation allows multiple API calls to be embedded into a single HTTP request.", + "parameters": [ + { + "$ref": "#/parameters/Body" + }, + { + "$ref": "#/parameters/ContentLengthBlob" + }, + { + "$ref": "#/parameters/MultipartContentType" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "202": { + "description": "Success.", + "headers": { + "Content-Type": { + "type": "string", + "description": "The media type of the body of the response. For batch requests, this is multipart/mixed; boundary=batchresponse_GUID" + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + } + }, + "schema": { + "type": "object", + "format": "file" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["batch"] + } + ] + }, + "/?comp=blobs": { + "get": { + "tags": ["service"], + "operationId": "Service_FilterBlobs", + "description": "The Filter Blobs operation enables callers to list blobs across all containers whose tags match a given search expression. Filter blobs searches across all containers within a storage account but can be scoped within the expression to a single container.", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/FilterBlobsWhere" + }, + { + "$ref": "#/parameters/Marker" + }, + { + "$ref": "#/parameters/MaxResultsBlob" + }, + { + "$ref": "#/parameters/FilterBlobsInclude" + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + }, + "schema": { + "$ref": "#/definitions/FilterBlobSegment" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["blobs"] + } + ] + }, + "/{containerName}?restype=container": { + "put": { + "tags": ["container"], + "operationId": "Container_Create", + "description": "creates a new container under the specified account. If the container with the same name already exists, the operation fails", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/Metadata" + }, + { + "$ref": "#/parameters/BlobPublicAccess" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/DefaultEncryptionScope" + }, + { + "$ref": "#/parameters/DenyEncryptionScopeOverride" + } + ], + "responses": { + "201": { + "description": "Success, Container created.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "get": { + "tags": ["container"], + "operationId": "Container_GetProperties", + "description": "returns all user-defined metadata and system properties for the specified container. The data returned does not include the container's list of blobs", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "x-ms-meta": { + "type": "string", + "x-ms-client-name": "Metadata", + "x-ms-header-collection-prefix": "x-ms-meta-" + }, + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-lease-duration": { + "x-ms-client-name": "LeaseDuration", + "description": "When a blob is leased, specifies whether the lease is of infinite or fixed duration.", + "type": "string", + "enum": ["infinite", "fixed"], + "x-ms-enum": { + "name": "LeaseDurationType", + "modelAsString": false + } + }, + "x-ms-lease-state": { + "x-ms-client-name": "LeaseState", + "description": "Lease state of the blob.", + "type": "string", + "enum": [ + "available", + "leased", + "expired", + "breaking", + "broken" + ], + "x-ms-enum": { + "name": "LeaseStateType", + "modelAsString": false + } + }, + "x-ms-lease-status": { + "x-ms-client-name": "LeaseStatus", + "description": "The current lease status of the blob.", + "type": "string", + "enum": ["locked", "unlocked"], + "x-ms-enum": { + "name": "LeaseStatusType", + "modelAsString": false + } + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-blob-public-access": { + "x-ms-client-name": "BlobPublicAccess", + "description": "Indicated whether data in the container may be accessed publicly and the level of access", + "type": "string", + "enum": ["container", "blob"], + "x-ms-enum": { + "name": "PublicAccessType", + "modelAsString": true + } + }, + "x-ms-has-immutability-policy": { + "x-ms-client-name": "HasImmutabilityPolicy", + "description": "Indicates whether the container has an immutability policy set on it.", + "type": "boolean" + }, + "x-ms-has-legal-hold": { + "x-ms-client-name": "HasLegalHold", + "description": "Indicates whether the container has a legal hold.", + "type": "boolean" + }, + "x-ms-default-encryption-scope": { + "x-ms-client-name": "DefaultEncryptionScope", + "description": "The default encryption scope for the container.", + "type": "string" + }, + "x-ms-deny-encryption-scope-override": { + "x-ms-client-name": "DenyEncryptionScopeOverride", + "description": "Indicates whether the container's default encryption scope can be overriden.", + "type": "boolean" + }, + "x-ms-immutable-storage-with-versioning-enabled": { + "x-ms-client-name": "IsImmutableStorageWithVersioningEnabled", + "description": "Indicates whether version level worm is enabled on a container.", + "type": "boolean" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "head": { + "tags": ["container"], + "operationId": "Container_GetPropertiesWithHead", + "description": "returns all user-defined metadata and system properties for the specified container. The data returned does not include the container's list of blobs", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "x-ms-meta": { + "type": "string", + "x-ms-client-name": "Metadata", + "x-ms-header-collection-prefix": "x-ms-meta-" + }, + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-lease-duration": { + "x-ms-client-name": "LeaseDuration", + "description": "When a blob is leased, specifies whether the lease is of infinite or fixed duration.", + "type": "string", + "enum": ["infinite", "fixed"], + "x-ms-enum": { + "name": "LeaseDurationType", + "modelAsString": false + } + }, + "x-ms-lease-state": { + "x-ms-client-name": "LeaseState", + "description": "Lease state of the blob.", + "type": "string", + "enum": [ + "available", + "leased", + "expired", + "breaking", + "broken" + ], + "x-ms-enum": { + "name": "LeaseStateType", + "modelAsString": false + } + }, + "x-ms-lease-status": { + "x-ms-client-name": "LeaseStatus", + "description": "The current lease status of the blob.", + "type": "string", + "enum": ["locked", "unlocked"], + "x-ms-enum": { + "name": "LeaseStatusType", + "modelAsString": false + } + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-blob-public-access": { + "x-ms-client-name": "BlobPublicAccess", + "description": "Indicated whether data in the container may be accessed publicly and the level of access", + "type": "string", + "enum": ["container", "blob"], + "x-ms-enum": { + "name": "PublicAccessType", + "modelAsString": true + } + }, + "x-ms-has-immutability-policy": { + "x-ms-client-name": "HasImmutabilityPolicy", + "description": "Indicates whether the container has an immutability policy set on it.", + "type": "boolean" + }, + "x-ms-has-legal-hold": { + "x-ms-client-name": "HasLegalHold", + "description": "Indicates whether the container has a legal hold.", + "type": "boolean" + }, + "x-ms-default-encryption-scope": { + "x-ms-client-name": "DefaultEncryptionScope", + "description": "The default encryption scope for the container.", + "type": "string" + }, + "x-ms-deny-encryption-scope-override": { + "x-ms-client-name": "DenyEncryptionScopeOverride", + "description": "Indicates whether the container's default encryption scope can be overriden.", + "type": "boolean" + }, + "x-ms-immutable-storage-with-versioning-enabled": { + "x-ms-client-name": "IsImmutableStorageWithVersioningEnabled", + "description": "Indicates whether version level worm is enabled on a container.", + "type": "boolean" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "delete": { + "tags": ["container"], + "operationId": "Container_Delete", + "description": "operation marks the specified container for deletion. The container and any blobs contained within it are later deleted during garbage collection", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "202": { + "description": "Accepted", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "restype", + "description": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": ["container"] + } + ] + }, + "/{containerName}?restype=container&comp=metadata": { + "put": { + "tags": ["container"], + "operationId": "Container_SetMetadata", + "description": "operation sets one or more user-defined name-value pairs for the specified container.", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/Metadata" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "restype", + "description": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": ["container"] + }, + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["metadata"] + } + ] + }, + "/{containerName}?restype=container&comp=acl": { + "get": { + "tags": ["container"], + "operationId": "Container_GetAccessPolicy", + "description": "gets the permissions for the specified container. The permissions indicate whether container data may be accessed publicly.", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "x-ms-blob-public-access": { + "x-ms-client-name": "BlobPublicAccess", + "description": "Indicated whether data in the container may be accessed publicly and the level of access", + "type": "string", + "enum": ["container", "blob"], + "x-ms-enum": { + "name": "PublicAccessType", + "modelAsString": true + } + }, + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + }, + "schema": { + "$ref": "#/definitions/SignedIdentifiers" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "put": { + "tags": ["container"], + "operationId": "Container_SetAccessPolicy", + "description": "sets the permissions for the specified container. The permissions indicate whether blobs in a container may be accessed publicly.", + "parameters": [ + { + "$ref": "#/parameters/ContainerAcl" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/BlobPublicAccess" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "Success.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "restype", + "description": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": ["container"] + }, + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["acl"] + } + ] + }, + "/{containerName}?restype=container&comp=undelete": { + "put": { + "tags": ["container"], + "operationId": "Container_Restore", + "description": "Restores a previously-deleted container.", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/DeletedContainerName" + }, + { + "$ref": "#/parameters/DeletedContainerVersion" + } + ], + "responses": { + "201": { + "description": "Created.", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "restype", + "description": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": ["container"] + }, + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["undelete"] + } + ] + }, + "/{containerName}?restype=container&comp=batch": { + "post": { + "tags": ["container"], + "operationId": "Container_SubmitBatch", + "description": "The Batch operation allows multiple API calls to be embedded into a single HTTP request.", + "parameters": [ + { + "$ref": "#/parameters/Body" + }, + { + "$ref": "#/parameters/ContentLengthBlob" + }, + { + "$ref": "#/parameters/MultipartContentType" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "202": { + "description": "Success.", + "headers": { + "Content-Type": { + "type": "string", + "description": "The media type of the body of the response. For batch requests, this is multipart/mixed; boundary=batchresponse_GUID" + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + } + }, + "schema": { + "type": "object", + "format": "file" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "restype", + "description": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": ["container"] + }, + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["batch"] + } + ] + }, + "/{containerName}?restype=container&comp=blobs": { + "get": { + "tags": ["container"], + "operationId": "Container_FilterBlobs", + "description": "The Filter Blobs operation enables callers to list blobs in a container whose tags match a given search expression. Filter blobs searches within the given container.", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/FilterBlobsWhere" + }, + { + "$ref": "#/parameters/Marker" + }, + { + "$ref": "#/parameters/MaxResultsBlob" + }, + { + "$ref": "#/parameters/FilterBlobsInclude" + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + }, + "schema": { + "$ref": "#/definitions/FilterBlobSegment" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "restype", + "description": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": ["container"] + }, + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["blobs"] + } + ] + }, + "/{containerName}?comp=lease&restype=container&acquire": { + "put": { + "tags": ["container"], + "operationId": "Container_AcquireLease", + "description": "[Update] establishes and manages a lock on a container for delete operations. The lock duration can be 15 to 60 seconds, or can be infinite", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/LeaseDurationBlob" + }, + { + "$ref": "#/parameters/ProposedLeaseIdOptional" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "201": { + "description": "The Acquire operation completed successfully.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-lease-id": { + "x-ms-client-name": "LeaseId", + "type": "string", + "description": "Uniquely identifies a container's lease" + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["lease"] + }, + { + "name": "restype", + "description": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": ["container"] + }, + { + "name": "x-ms-lease-action", + "x-ms-client-name": "action", + "in": "header", + "required": true, + "type": "string", + "enum": ["acquire"], + "x-ms-enum": { + "name": "LeaseAction", + "modelAsString": false + }, + "x-ms-parameter-location": "method", + "description": "Describes what lease action to take." + } + ] + }, + "/{containerName}?comp=lease&restype=container&release": { + "put": { + "tags": ["container"], + "operationId": "Container_ReleaseLease", + "description": "[Update] establishes and manages a lock on a container for delete operations. The lock duration can be 15 to 60 seconds, or can be infinite", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/LeaseIdRequired" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "The Release operation completed successfully.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["lease"] + }, + { + "name": "restype", + "description": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": ["container"] + }, + { + "name": "x-ms-lease-action", + "x-ms-client-name": "action", + "in": "header", + "required": true, + "type": "string", + "enum": ["release"], + "x-ms-enum": { + "name": "LeaseAction", + "modelAsString": false + }, + "x-ms-parameter-location": "method", + "description": "Describes what lease action to take." + } + ] + }, + "/{containerName}?comp=lease&restype=container&renew": { + "put": { + "tags": ["container"], + "operationId": "Container_RenewLease", + "description": "[Update] establishes and manages a lock on a container for delete operations. The lock duration can be 15 to 60 seconds, or can be infinite", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/LeaseIdRequired" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "The Renew operation completed successfully.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-lease-id": { + "x-ms-client-name": "LeaseId", + "type": "string", + "description": "Uniquely identifies a container's lease" + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["lease"] + }, + { + "name": "restype", + "description": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": ["container"] + }, + { + "name": "x-ms-lease-action", + "x-ms-client-name": "action", + "in": "header", + "required": true, + "type": "string", + "enum": ["renew"], + "x-ms-enum": { + "name": "LeaseAction", + "modelAsString": false + }, + "x-ms-parameter-location": "method", + "description": "Describes what lease action to take." + } + ] + }, + "/{containerName}?comp=lease&restype=container&break": { + "put": { + "tags": ["container"], + "operationId": "Container_BreakLease", + "description": "[Update] establishes and manages a lock on a container for delete operations. The lock duration can be 15 to 60 seconds, or can be infinite", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/LeaseBreakPeriod" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "202": { + "description": "The Break operation completed successfully.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-lease-time": { + "x-ms-client-name": "LeaseTime", + "type": "integer", + "description": "Approximate time remaining in the lease period, in seconds." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["lease"] + }, + { + "name": "restype", + "description": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": ["container"] + }, + { + "name": "x-ms-lease-action", + "x-ms-client-name": "action", + "in": "header", + "required": true, + "type": "string", + "enum": ["break"], + "x-ms-enum": { + "name": "LeaseAction", + "modelAsString": false + }, + "x-ms-parameter-location": "method", + "description": "Describes what lease action to take." + } + ] + }, + "/{containerName}?comp=lease&restype=container&change": { + "put": { + "tags": ["container"], + "operationId": "Container_ChangeLease", + "description": "[Update] establishes and manages a lock on a container for delete operations. The lock duration can be 15 to 60 seconds, or can be infinite", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/LeaseIdRequired" + }, + { + "$ref": "#/parameters/ProposedLeaseIdRequired" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "The Change operation completed successfully.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-lease-id": { + "x-ms-client-name": "LeaseId", + "type": "string", + "description": "Uniquely identifies a container's lease" + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["lease"] + }, + { + "name": "restype", + "description": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": ["container"] + }, + { + "name": "x-ms-lease-action", + "x-ms-client-name": "action", + "in": "header", + "required": true, + "type": "string", + "enum": ["change"], + "x-ms-enum": { + "name": "LeaseAction", + "modelAsString": false + }, + "x-ms-parameter-location": "method", + "description": "Describes what lease action to take." + } + ] + }, + "/{containerName}?restype=account&comp=properties": { + "get": { + "tags": ["container"], + "operationId": "Container_GetAccountInfo", + "description": "Returns the sku name and account kind ", + "parameters": [ + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Success (OK)", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-sku-name": { + "x-ms-client-name": "SkuName", + "type": "string", + "enum": [ + "Standard_LRS", + "Standard_GRS", + "Standard_RAGRS", + "Standard_ZRS", + "Premium_LRS" + ], + "x-ms-enum": { + "name": "SkuName", + "modelAsString": false + }, + "description": "Identifies the sku name of the account" + }, + "x-ms-account-kind": { + "x-ms-client-name": "AccountKind", + "type": "string", + "enum": [ + "Storage", + "BlobStorage", + "StorageV2", + "FileStorage", + "BlockBlobStorage" + ], + "x-ms-enum": { + "name": "AccountKind", + "modelAsString": false + }, + "description": "Identifies the account kind" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "head": { + "tags": ["container"], + "operationId": "Container_GetAccountInfoWithHead", + "description": "Returns the sku name and account kind ", + "parameters": [ + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Success (OK)", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-sku-name": { + "x-ms-client-name": "SkuName", + "type": "string", + "enum": [ + "Standard_LRS", + "Standard_GRS", + "Standard_RAGRS", + "Standard_ZRS", + "Premium_LRS" + ], + "x-ms-enum": { + "name": "SkuName", + "modelAsString": false + }, + "description": "Identifies the sku name of the account" + }, + "x-ms-account-kind": { + "x-ms-client-name": "AccountKind", + "type": "string", + "enum": [ + "Storage", + "BlobStorage", + "StorageV2", + "FileStorage", + "BlockBlobStorage" + ], + "x-ms-enum": { + "name": "AccountKind", + "modelAsString": false + }, + "description": "Identifies the account kind" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "restype", + "description": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": ["account"] + }, + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["properties"] + } + ] + }, + "/{containerName}/{blob}?PageBlob": { + "put": { + "tags": ["blob"], + "operationId": "PageBlob_Create", + "description": "The Create operation creates a new page blob.", + "consumes": ["application/octet-stream"], + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ContentLengthBlob" + }, + { + "$ref": "#/parameters/PremiumPageBlobAccessTierOptional" + }, + { + "$ref": "#/parameters/BlobContentType" + }, + { + "$ref": "#/parameters/BlobContentEncoding" + }, + { + "$ref": "#/parameters/BlobContentLanguage" + }, + { + "$ref": "#/parameters/BlobContentMD5" + }, + { + "$ref": "#/parameters/BlobCacheControl" + }, + { + "$ref": "#/parameters/Metadata" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/BlobContentDisposition" + }, + { + "$ref": "#/parameters/EncryptionKey" + }, + { + "$ref": "#/parameters/EncryptionKeySha256" + }, + { + "$ref": "#/parameters/EncryptionAlgorithm" + }, + { + "$ref": "#/parameters/EncryptionScope" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/BlobContentLengthRequired" + }, + { + "$ref": "#/parameters/BlobSequenceNumber" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/BlobTagsHeader" + }, + { + "$ref": "#/parameters/ImmutabilityPolicyExpiry" + }, + { + "$ref": "#/parameters/ImmutabilityPolicyMode" + }, + { + "$ref": "#/parameters/LegalHoldOptional" + } + ], + "responses": { + "201": { + "description": "The blob was created.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "Content-MD5": { + "type": "string", + "format": "byte", + "description": "If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the client can check for message content integrity." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "x-ms-version-id": { + "x-ms-client-name": "VersionId", + "type": "string", + "description": "A DateTime value returned by the service that uniquely identifies the blob. The value of this header indicates the blob version, and may be used in subsequent requests to access this version of the blob." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-request-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the contents of the request are successfully encrypted using the specified algorithm, and false otherwise." + }, + "x-ms-encryption-key-sha256": { + "x-ms-client-name": "EncryptionKeySha256", + "type": "string", + "description": "The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned when the blob was encrypted with a customer-provided key." + }, + "x-ms-encryption-scope": { + "x-ms-client-name": "EncryptionScope", + "type": "string", + "description": "Returns the name of the encryption scope used to encrypt the blob contents and application metadata. Note that the absence of this header implies use of the default account encryption scope." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "x-ms-blob-type", + "x-ms-client-name": "blobType", + "in": "header", + "required": true, + "x-ms-parameter-location": "method", + "description": "Specifies the type of blob to create: block blob, page blob, or append blob.", + "type": "string", + "enum": ["PageBlob"], + "x-ms-enum": { + "name": "BlobType", + "modelAsString": false + } + } + ] + }, + "/{containerName}/{blob}?AppendBlob": { + "put": { + "tags": ["blob"], + "operationId": "AppendBlob_Create", + "description": "The Create Append Blob operation creates a new append blob.", + "consumes": ["application/octet-stream"], + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ContentLengthBlob" + }, + { + "$ref": "#/parameters/BlobContentType" + }, + { + "$ref": "#/parameters/BlobContentEncoding" + }, + { + "$ref": "#/parameters/BlobContentLanguage" + }, + { + "$ref": "#/parameters/BlobContentMD5" + }, + { + "$ref": "#/parameters/BlobCacheControl" + }, + { + "$ref": "#/parameters/Metadata" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/BlobContentDisposition" + }, + { + "$ref": "#/parameters/EncryptionKey" + }, + { + "$ref": "#/parameters/EncryptionKeySha256" + }, + { + "$ref": "#/parameters/EncryptionAlgorithm" + }, + { + "$ref": "#/parameters/EncryptionScope" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/BlobTagsHeader" + }, + { + "$ref": "#/parameters/ImmutabilityPolicyExpiry" + }, + { + "$ref": "#/parameters/ImmutabilityPolicyMode" + }, + { + "$ref": "#/parameters/LegalHoldOptional" + } + ], + "responses": { + "201": { + "description": "The blob was created.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "Content-MD5": { + "type": "string", + "format": "byte", + "description": "If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the client can check for message content integrity." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "x-ms-version-id": { + "x-ms-client-name": "VersionId", + "type": "string", + "description": "A DateTime value returned by the service that uniquely identifies the blob. The value of this header indicates the blob version, and may be used in subsequent requests to access this version of the blob." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-request-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the contents of the request are successfully encrypted using the specified algorithm, and false otherwise." + }, + "x-ms-encryption-key-sha256": { + "x-ms-client-name": "EncryptionKeySha256", + "type": "string", + "description": "The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned when the blob was encrypted with a customer-provided key." + }, + "x-ms-encryption-scope": { + "x-ms-client-name": "EncryptionScope", + "type": "string", + "description": "Returns the name of the encryption scope used to encrypt the blob contents and application metadata. Note that the absence of this header implies use of the default account encryption scope." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "x-ms-blob-type", + "x-ms-client-name": "blobType", + "in": "header", + "required": true, + "x-ms-parameter-location": "method", + "description": "Specifies the type of blob to create: block blob, page blob, or append blob.", + "type": "string", + "enum": ["AppendBlob"], + "x-ms-enum": { + "name": "BlobType", + "modelAsString": false + } + } + ] + }, + "/{containerName}/{blob}?BlockBlob": { + "put": { + "tags": ["blob"], + "operationId": "BlockBlob_Upload", + "description": "The Upload Block Blob operation updates the content of an existing block blob. Updating an existing block blob overwrites any existing metadata on the blob. Partial updates are not supported with Put Blob; the content of the existing blob is overwritten with the content of the new blob. To perform a partial update of the content of a block blob, use the Put Block List operation.", + "consumes": ["application/octet-stream"], + "parameters": [ + { + "$ref": "#/parameters/Body" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ContentMD5Blob" + }, + { + "$ref": "#/parameters/ContentLengthBlob" + }, + { + "$ref": "#/parameters/BlobContentType" + }, + { + "$ref": "#/parameters/BlobContentEncoding" + }, + { + "$ref": "#/parameters/BlobContentLanguage" + }, + { + "$ref": "#/parameters/BlobContentMD5" + }, + { + "$ref": "#/parameters/BlobCacheControl" + }, + { + "$ref": "#/parameters/Metadata" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/BlobContentDisposition" + }, + { + "$ref": "#/parameters/EncryptionKey" + }, + { + "$ref": "#/parameters/EncryptionKeySha256" + }, + { + "$ref": "#/parameters/EncryptionAlgorithm" + }, + { + "$ref": "#/parameters/EncryptionScope" + }, + { + "$ref": "#/parameters/AccessTierOptional" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/BlobTagsHeader" + }, + { + "$ref": "#/parameters/ImmutabilityPolicyExpiry" + }, + { + "$ref": "#/parameters/ImmutabilityPolicyMode" + }, + { + "$ref": "#/parameters/LegalHoldOptional" + }, + { + "$ref": "#/parameters/ContentCrc64" + } + ], + "responses": { + "201": { + "description": "The blob was updated.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "Content-MD5": { + "type": "string", + "format": "byte", + "description": "If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the client can check for message content integrity." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "x-ms-version-id": { + "x-ms-client-name": "VersionId", + "type": "string", + "description": "A DateTime value returned by the service that uniquely identifies the blob. The value of this header indicates the blob version, and may be used in subsequent requests to access this version of the blob." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-request-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the contents of the request are successfully encrypted using the specified algorithm, and false otherwise." + }, + "x-ms-encryption-key-sha256": { + "x-ms-client-name": "EncryptionKeySha256", + "type": "string", + "description": "The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned when the blob was encrypted with a customer-provided key." + }, + "x-ms-encryption-scope": { + "x-ms-client-name": "EncryptionScope", + "type": "string", + "description": "Returns the name of the encryption scope used to encrypt the blob contents and application metadata. Note that the absence of this header implies use of the default account encryption scope." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "x-ms-blob-type", + "x-ms-client-name": "blobType", + "in": "header", + "required": true, + "x-ms-parameter-location": "method", + "description": "Specifies the type of blob to create: block blob, page blob, or append blob.", + "type": "string", + "enum": ["BlockBlob"], + "x-ms-enum": { + "name": "BlobType", + "modelAsString": false + } + } + ] + }, + "/{containerName}/{blob}?BlockBlob&fromUrl": { + "put": { + "tags": ["blob"], + "operationId": "BlockBlob_PutBlobFromUrl", + "description": "The Put Blob from URL operation creates a new Block Blob where the contents of the blob are read from a given URL. This API is supported beginning with the 2020-04-08 version. Partial updates are not supported with Put Blob from URL; the content of an existing blob is overwritten with the content of the new blob. To perform partial updates to a block blob’s contents using a source URL, use the Put Block from URL API in conjunction with Put Block List.", + "consumes": ["application/octet-stream"], + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ContentMD5Blob" + }, + { + "$ref": "#/parameters/ContentLengthBlob" + }, + { + "$ref": "#/parameters/BlobContentType" + }, + { + "$ref": "#/parameters/BlobContentEncoding" + }, + { + "$ref": "#/parameters/BlobContentLanguage" + }, + { + "$ref": "#/parameters/BlobContentMD5" + }, + { + "$ref": "#/parameters/BlobCacheControl" + }, + { + "$ref": "#/parameters/Metadata" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/BlobContentDisposition" + }, + { + "$ref": "#/parameters/EncryptionKey" + }, + { + "$ref": "#/parameters/EncryptionKeySha256" + }, + { + "$ref": "#/parameters/EncryptionAlgorithm" + }, + { + "$ref": "#/parameters/EncryptionScope" + }, + { + "$ref": "#/parameters/AccessTierOptional" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/SourceIfModifiedSince" + }, + { + "$ref": "#/parameters/SourceIfUnmodifiedSince" + }, + { + "$ref": "#/parameters/SourceIfMatch" + }, + { + "$ref": "#/parameters/SourceIfNoneMatch" + }, + { + "$ref": "#/parameters/SourceIfTags" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/SourceContentMD5" + }, + { + "$ref": "#/parameters/BlobTagsHeader" + }, + { + "$ref": "#/parameters/CopySource" + }, + { + "$ref": "#/parameters/CopySourceBlobProperties" + }, + { + "$ref": "#/parameters/CopySourceAuthorization" + }, + { + "$ref": "#/parameters/CopySourceTags" + } + ], + "responses": { + "201": { + "description": "The blob was updated.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "Content-MD5": { + "type": "string", + "format": "byte", + "description": "If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the client can check for message content integrity." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "x-ms-version-id": { + "x-ms-client-name": "VersionId", + "type": "string", + "description": "A DateTime value returned by the service that uniquely identifies the blob. The value of this header indicates the blob version, and may be used in subsequent requests to access this version of the blob." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-request-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the contents of the request are successfully encrypted using the specified algorithm, and false otherwise." + }, + "x-ms-encryption-key-sha256": { + "x-ms-client-name": "EncryptionKeySha256", + "type": "string", + "description": "The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned when the blob was encrypted with a customer-provided key." + }, + "x-ms-encryption-scope": { + "x-ms-client-name": "EncryptionScope", + "type": "string", + "description": "Returns the name of the encryption scope used to encrypt the blob contents and application metadata. Note that the absence of this header implies use of the default account encryption scope." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "x-ms-blob-type", + "x-ms-client-name": "blobType", + "in": "header", + "required": true, + "x-ms-parameter-location": "method", + "description": "Specifies the type of blob to create: block blob, page blob, or append blob.", + "type": "string", + "enum": ["BlockBlob"], + "x-ms-enum": { + "name": "BlobType", + "modelAsString": false + } + } + ] + }, + "/{containerName}/{blob}?comp=undelete": { + "put": { + "tags": ["blob"], + "operationId": "Blob_Undelete", + "description": "Undelete a blob that was previously soft deleted", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "The blob was undeleted successfully.", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["undelete"] + } + ] + }, + "/{containerName}/{blob}?comp=expiry": { + "put": { + "tags": ["blob"], + "operationId": "Blob_SetExpiry", + "description": "Sets the time a blob will expire and be deleted.", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/BlobExpiryOptions" + }, + { + "$ref": "#/parameters/BlobExpiryTime" + } + ], + "responses": { + "200": { + "description": "The blob expiry was set successfully.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["expiry"] + } + ] + }, + "/{containerName}/{blob}?comp=properties&SetHTTPHeaders": { + "put": { + "tags": ["blob"], + "operationId": "Blob_SetHTTPHeaders", + "description": "The Set HTTP Headers operation sets system properties on the blob", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/BlobCacheControl" + }, + { + "$ref": "#/parameters/BlobContentType" + }, + { + "$ref": "#/parameters/BlobContentMD5" + }, + { + "$ref": "#/parameters/BlobContentEncoding" + }, + { + "$ref": "#/parameters/BlobContentLanguage" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/BlobContentDisposition" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "The properties were set successfully.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-blob-sequence-number": { + "x-ms-client-name": "BlobSequenceNumber", + "type": "integer", + "format": "int64", + "description": "The current sequence number for a page blob. This header is not returned for block blobs or append blobs" + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["properties"] + } + ] + }, + "/{containerName}/{blob}?comp=immutabilityPolicies": { + "put": { + "tags": ["blob"], + "operationId": "Blob_SetImmutabilityPolicy", + "description": "The Set Immutability Policy operation sets the immutability policy on the blob", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/ImmutabilityPolicyExpiry" + }, + { + "$ref": "#/parameters/ImmutabilityPolicyMode" + } + ], + "responses": { + "200": { + "description": "The immutability policy was successfully set.", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-immutability-policy-until-date": { + "x-ms-client-name": "ImmutabilityPolicyExpiry", + "type": "string", + "format": "date-time-rfc1123", + "description": "Indicates the time the immutability policy will expire." + }, + "x-ms-immutability-policy-mode": { + "x-ms-client-name": "ImmutabilityPolicyMode", + "type": "string", + "enum": ["Mutable", "Unlocked", "Locked"], + "x-ms-enum": { + "name": "BlobImmutabilityPolicyMode", + "modelAsString": false + }, + "description": "Indicates immutability policy mode." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "delete": { + "tags": ["blob"], + "operationId": "Blob_DeleteImmutabilityPolicy", + "description": "The Delete Immutability Policy operation deletes the immutability policy on the blob", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "The delete immutability policy request was accepted and the immutability policy will be deleted.", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["immutabilityPolicies"] + } + ] + }, + "/{containerName}/{blob}?comp=legalhold": { + "put": { + "tags": ["blob"], + "operationId": "Blob_SetLegalHold", + "description": "The Set Legal Hold operation sets a legal hold on the blob.", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/LegalHoldRequired" + } + ], + "responses": { + "200": { + "description": "The legal hold was successfully set on the blob.", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-legal-hold": { + "x-ms-client-name": "LegalHold", + "type": "boolean", + "description": "Indicates if the blob has a legal hold." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["legalhold"] + } + ] + }, + "/{containerName}/{blob}?comp=metadata": { + "put": { + "tags": ["blob"], + "operationId": "Blob_SetMetadata", + "description": "The Set Blob Metadata operation sets user-defined metadata for the specified blob as one or more name-value pairs", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/Metadata" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/EncryptionKey" + }, + { + "$ref": "#/parameters/EncryptionKeySha256" + }, + { + "$ref": "#/parameters/EncryptionAlgorithm" + }, + { + "$ref": "#/parameters/EncryptionScope" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "The metadata was set successfully.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "x-ms-version-id": { + "x-ms-client-name": "VersionId", + "type": "string", + "description": "A DateTime value returned by the service that uniquely identifies the blob. The value of this header indicates the blob version, and may be used in subsequent requests to access this version of the blob." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-request-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the contents of the request are successfully encrypted using the specified algorithm, and false otherwise." + }, + "x-ms-encryption-key-sha256": { + "x-ms-client-name": "EncryptionKeySha256", + "type": "string", + "description": "The SHA-256 hash of the encryption key used to encrypt the metadata. This header is only returned when the metadata was encrypted with a customer-provided key." + }, + "x-ms-encryption-scope": { + "x-ms-client-name": "EncryptionScope", + "type": "string", + "description": "Returns the name of the encryption scope used to encrypt the blob contents and application metadata. Note that the absence of this header implies use of the default account encryption scope." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["metadata"] + } + ] + }, + "/{containerName}/{blob}?comp=lease&acquire": { + "put": { + "tags": ["blob"], + "operationId": "Blob_AcquireLease", + "description": "[Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete operations", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/LeaseDurationBlob" + }, + { + "$ref": "#/parameters/ProposedLeaseIdOptional" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "201": { + "description": "The Acquire operation completed successfully.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the blob was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-lease-id": { + "x-ms-client-name": "LeaseId", + "type": "string", + "description": "Uniquely identifies a blobs' lease" + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["lease"] + }, + { + "name": "x-ms-lease-action", + "x-ms-client-name": "action", + "in": "header", + "required": true, + "type": "string", + "enum": ["acquire"], + "x-ms-enum": { + "name": "LeaseAction", + "modelAsString": false + }, + "x-ms-parameter-location": "method", + "description": "Describes what lease action to take." + } + ] + }, + "/{containerName}/{blob}?comp=lease&release": { + "put": { + "tags": ["blob"], + "operationId": "Blob_ReleaseLease", + "description": "[Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete operations", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/LeaseIdRequired" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "The Release operation completed successfully.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the blob was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["lease"] + }, + { + "name": "x-ms-lease-action", + "x-ms-client-name": "action", + "in": "header", + "required": true, + "type": "string", + "enum": ["release"], + "x-ms-enum": { + "name": "LeaseAction", + "modelAsString": false + }, + "x-ms-parameter-location": "method", + "description": "Describes what lease action to take." + } + ] + }, + "/{containerName}/{blob}?comp=lease&renew": { + "put": { + "tags": ["blob"], + "operationId": "Blob_RenewLease", + "description": "[Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete operations", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/LeaseIdRequired" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "The Renew operation completed successfully.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the blob was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-lease-id": { + "x-ms-client-name": "LeaseId", + "type": "string", + "description": "Uniquely identifies a blobs' lease" + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["lease"] + }, + { + "name": "x-ms-lease-action", + "x-ms-client-name": "action", + "in": "header", + "required": true, + "type": "string", + "enum": ["renew"], + "x-ms-enum": { + "name": "LeaseAction", + "modelAsString": false + }, + "x-ms-parameter-location": "method", + "description": "Describes what lease action to take." + } + ] + }, + "/{containerName}/{blob}?comp=lease&change": { + "put": { + "tags": ["blob"], + "operationId": "Blob_ChangeLease", + "description": "[Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete operations", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/LeaseIdRequired" + }, + { + "$ref": "#/parameters/ProposedLeaseIdRequired" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "The Change operation completed successfully.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the blob was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-lease-id": { + "x-ms-client-name": "LeaseId", + "type": "string", + "description": "Uniquely identifies a blobs' lease" + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["lease"] + }, + { + "name": "x-ms-lease-action", + "x-ms-client-name": "action", + "in": "header", + "required": true, + "type": "string", + "enum": ["change"], + "x-ms-enum": { + "name": "LeaseAction", + "modelAsString": false + }, + "x-ms-parameter-location": "method", + "description": "Describes what lease action to take." + } + ] + }, + "/{containerName}/{blob}?comp=lease&break": { + "put": { + "tags": ["blob"], + "operationId": "Blob_BreakLease", + "description": "[Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete operations", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/LeaseBreakPeriod" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "202": { + "description": "The Break operation completed successfully.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the blob was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-lease-time": { + "x-ms-client-name": "LeaseTime", + "type": "integer", + "description": "Approximate time remaining in the lease period, in seconds." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["lease"] + }, + { + "name": "x-ms-lease-action", + "x-ms-client-name": "action", + "in": "header", + "required": true, + "type": "string", + "enum": ["break"], + "x-ms-enum": { + "name": "LeaseAction", + "modelAsString": false + }, + "x-ms-parameter-location": "method", + "description": "Describes what lease action to take." + } + ] + }, + "/{containerName}/{blob}?comp=snapshot": { + "put": { + "tags": ["blob"], + "operationId": "Blob_CreateSnapshot", + "description": "The Create Snapshot operation creates a read-only snapshot of a blob", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/Metadata" + }, + { + "$ref": "#/parameters/EncryptionKey" + }, + { + "$ref": "#/parameters/EncryptionKeySha256" + }, + { + "$ref": "#/parameters/EncryptionAlgorithm" + }, + { + "$ref": "#/parameters/EncryptionScope" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "201": { + "description": "The snaptshot was taken successfully.", + "headers": { + "x-ms-snapshot": { + "x-ms-client-name": "Snapshot", + "type": "string", + "description": "Uniquely identifies the snapshot and indicates the snapshot version. It may be used in subsequent requests to access the snapshot" + }, + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "x-ms-version-id": { + "x-ms-client-name": "VersionId", + "type": "string", + "description": "A DateTime value returned by the service that uniquely identifies the blob. The value of this header indicates the blob version, and may be used in subsequent requests to access this version of the blob." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-request-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "True if the contents of the request are successfully encrypted using the specified algorithm, and false otherwise. For a snapshot request, this header is set to true when metadata was provided in the request and encrypted with a customer-provided key." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["snapshot"] + } + ] + }, + "/{containerName}/{blob}?comp=copy": { + "put": { + "tags": ["blob"], + "operationId": "Blob_StartCopyFromURL", + "description": "The Start Copy From URL operation copies a blob or an internet resource to a new blob.", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/Metadata" + }, + { + "$ref": "#/parameters/AccessTierOptional" + }, + { + "$ref": "#/parameters/RehydratePriority" + }, + { + "$ref": "#/parameters/SourceIfModifiedSince" + }, + { + "$ref": "#/parameters/SourceIfUnmodifiedSince" + }, + { + "$ref": "#/parameters/SourceIfMatch" + }, + { + "$ref": "#/parameters/SourceIfNoneMatch" + }, + { + "$ref": "#/parameters/SourceIfTags" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/CopySource" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/BlobTagsHeader" + }, + { + "$ref": "#/parameters/SealBlob" + }, + { + "$ref": "#/parameters/ImmutabilityPolicyExpiry" + }, + { + "$ref": "#/parameters/ImmutabilityPolicyMode" + }, + { + "$ref": "#/parameters/LegalHoldOptional" + } + ], + "responses": { + "202": { + "description": "The copy blob has been accepted with the specified copy status.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "x-ms-version-id": { + "x-ms-client-name": "VersionId", + "type": "string", + "description": "A DateTime value returned by the service that uniquely identifies the blob. The value of this header indicates the blob version, and may be used in subsequent requests to access this version of the blob." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-copy-id": { + "x-ms-client-name": "CopyId", + "type": "string", + "description": "String identifier for this copy operation. Use with Get Blob Properties to check the status of this copy operation, or pass to Abort Copy Blob to abort a pending copy." + }, + "x-ms-copy-status": { + "x-ms-client-name": "CopyStatus", + "description": "State of the copy operation identified by x-ms-copy-id.", + "type": "string", + "enum": ["pending", "success", "aborted", "failed"], + "x-ms-enum": { + "name": "CopyStatusType", + "modelAsString": false + } + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + } + }, + "/{containerName}/{blob}?comp=copy&sync": { + "put": { + "tags": ["blob"], + "operationId": "Blob_CopyFromURL", + "description": "The Copy From URL operation copies a blob or an internet resource to a new blob. It will not return a response until the copy is complete.", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/Metadata" + }, + { + "$ref": "#/parameters/AccessTierOptional" + }, + { + "$ref": "#/parameters/SourceIfModifiedSince" + }, + { + "$ref": "#/parameters/SourceIfUnmodifiedSince" + }, + { + "$ref": "#/parameters/SourceIfMatch" + }, + { + "$ref": "#/parameters/SourceIfNoneMatch" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/CopySource" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/SourceContentMD5" + }, + { + "$ref": "#/parameters/BlobTagsHeader" + }, + { + "$ref": "#/parameters/ImmutabilityPolicyExpiry" + }, + { + "$ref": "#/parameters/ImmutabilityPolicyMode" + }, + { + "$ref": "#/parameters/LegalHoldOptional" + }, + { + "$ref": "#/parameters/CopySourceAuthorization" + }, + { + "$ref": "#/parameters/EncryptionScope" + }, + { + "$ref": "#/parameters/CopySourceTags" + } + ], + "responses": { + "202": { + "description": "The copy has completed.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "x-ms-version-id": { + "x-ms-client-name": "VersionId", + "type": "string", + "description": "A DateTime value returned by the service that uniquely identifies the blob. The value of this header indicates the blob version, and may be used in subsequent requests to access this version of the blob." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-copy-id": { + "x-ms-client-name": "CopyId", + "type": "string", + "description": "String identifier for this copy operation." + }, + "x-ms-copy-status": { + "x-ms-client-name": "CopyStatus", + "description": "State of the copy operation identified by x-ms-copy-id.", + "type": "string", + "enum": ["success"], + "x-ms-enum": { + "name": "SyncCopyStatusType", + "modelAsString": false + } + }, + "Content-MD5": { + "type": "string", + "format": "byte", + "description": "This response header is returned so that the client can check for the integrity of the copied content. This header is only returned if the source content MD5 was specified." + }, + "x-ms-content-crc64": { + "type": "string", + "format": "byte", + "description": "This response header is returned so that the client can check for the integrity of the copied content." + }, + "x-ms-encryption-scope": { + "x-ms-client-name": "EncryptionScope", + "type": "string", + "description": "Returns the name of the encryption scope used to encrypt the blob contents and application metadata. Note that the absence of this header implies use of the default account encryption scope." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "x-ms-requires-sync", + "description": "This header indicates that this is a synchronous Copy Blob From URL instead of a Asynchronous Copy Blob.", + "in": "header", + "required": true, + "type": "string", + "enum": ["true"] + } + ] + }, + "/{containerName}/{blob}?comp=copy©id": { + "put": { + "tags": ["blob"], + "operationId": "Blob_AbortCopyFromURL", + "description": "The Abort Copy From URL operation aborts a pending Copy From URL operation, and leaves a destination blob with zero length and full metadata.", + "parameters": [ + { + "$ref": "#/parameters/CopyId" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "204": { + "description": "The delete request was accepted and the blob will be deleted.", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["copy"] + }, + { + "name": "x-ms-copy-action", + "description": "Copy action.", + "x-ms-client-name": "copyActionAbortConstant", + "in": "header", + "required": true, + "type": "string", + "enum": ["abort"], + "x-ms-parameter-location": "method" + } + ] + }, + "/{containerName}/{blob}?comp=tier": { + "put": { + "tags": ["blobs"], + "operationId": "Blob_SetTier", + "description": "The Set Tier operation sets the tier on a blob. The operation is allowed on a page blob in a premium storage account and on a block blob in a blob storage account (locally redundant storage only). A premium page blob's tier determines the allowed size, IOPS, and bandwidth of the blob. A block blob's tier determines Hot/Cool/Archive storage type. This operation does not update the blob's ETag.", + "parameters": [ + { + "$ref": "#/parameters/Snapshot" + }, + { + "$ref": "#/parameters/VersionId" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/AccessTierRequired" + }, + { + "$ref": "#/parameters/RehydratePriority" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/IfTags" + } + ], + "responses": { + "200": { + "description": "The new tier will take effect immediately.", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and newer." + } + } + }, + "202": { + "description": "The transition to the new tier is pending.", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and newer." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["tier"] + } + ] + }, + "/{containerName}/{blob}?restype=account&comp=properties": { + "get": { + "tags": ["blob"], + "operationId": "Blob_GetAccountInfo", + "description": "Returns the sku name and account kind ", + "parameters": [ + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Success (OK)", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-sku-name": { + "x-ms-client-name": "SkuName", + "type": "string", + "enum": [ + "Standard_LRS", + "Standard_GRS", + "Standard_RAGRS", + "Standard_ZRS", + "Premium_LRS" + ], + "x-ms-enum": { + "name": "SkuName", + "modelAsString": false + }, + "description": "Identifies the sku name of the account" + }, + "x-ms-account-kind": { + "x-ms-client-name": "AccountKind", + "type": "string", + "enum": [ + "Storage", + "BlobStorage", + "StorageV2", + "FileStorage", + "BlockBlobStorage" + ], + "x-ms-enum": { + "name": "AccountKind", + "modelAsString": false + }, + "description": "Identifies the account kind" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "head": { + "tags": ["blob"], + "operationId": "Blob_GetAccountInfoWithHead", + "description": "Returns the sku name and account kind ", + "parameters": [ + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Success (OK)", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-sku-name": { + "x-ms-client-name": "SkuName", + "type": "string", + "enum": [ + "Standard_LRS", + "Standard_GRS", + "Standard_RAGRS", + "Standard_ZRS", + "Premium_LRS" + ], + "x-ms-enum": { + "name": "SkuName", + "modelAsString": false + }, + "description": "Identifies the sku name of the account" + }, + "x-ms-account-kind": { + "x-ms-client-name": "AccountKind", + "type": "string", + "enum": [ + "Storage", + "BlobStorage", + "StorageV2", + "FileStorage", + "BlockBlobStorage" + ], + "x-ms-enum": { + "name": "AccountKind", + "modelAsString": false + }, + "description": "Identifies the account kind" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "restype", + "description": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": ["account"] + }, + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["properties"] + } + ] + }, + "/{containerName}/{blob}?comp=block": { + "put": { + "tags": ["blockblob"], + "operationId": "BlockBlob_StageBlock", + "description": "The Stage Block operation creates a new block to be committed as part of a blob", + "consumes": ["application/octet-stream"], + "parameters": [ + { + "$ref": "#/parameters/BlockId" + }, + { + "$ref": "#/parameters/ContentLengthBlob" + }, + { + "$ref": "#/parameters/ContentMD5Blob" + }, + { + "$ref": "#/parameters/ContentCrc64" + }, + { + "$ref": "#/parameters/Body" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/EncryptionKey" + }, + { + "$ref": "#/parameters/EncryptionKeySha256" + }, + { + "$ref": "#/parameters/EncryptionAlgorithm" + }, + { + "$ref": "#/parameters/EncryptionScope" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "201": { + "description": "The block was created.", + "headers": { + "Content-MD5": { + "type": "string", + "format": "byte", + "description": "This header is returned so that the client can check for message content integrity. The value of this header is computed by the Blob service; it is not necessarily the same value specified in the request headers." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-content-crc64": { + "type": "string", + "format": "byte", + "description": "This header is returned so that the client can check for message content integrity. The value of this header is computed by the Blob service; it is not necessarily the same value specified in the request headers." + }, + "x-ms-request-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the contents of the request are successfully encrypted using the specified algorithm, and false otherwise." + }, + "x-ms-encryption-key-sha256": { + "x-ms-client-name": "EncryptionKeySha256", + "type": "string", + "description": "The SHA-256 hash of the encryption key used to encrypt the block. This header is only returned when the block was encrypted with a customer-provided key." + }, + "x-ms-encryption-scope": { + "x-ms-client-name": "EncryptionScope", + "type": "string", + "description": "Returns the name of the encryption scope used to encrypt the blob contents and application metadata. Note that the absence of this header implies use of the default account encryption scope." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["block"] + } + ] + }, + "/{containerName}/{blob}?comp=block&fromURL": { + "put": { + "tags": ["blockblob"], + "operationId": "BlockBlob_StageBlockFromURL", + "description": "The Stage Block operation creates a new block to be committed as part of a blob where the contents are read from a URL.", + "parameters": [ + { + "$ref": "#/parameters/BlockId" + }, + { + "$ref": "#/parameters/ContentLengthBlob" + }, + { + "$ref": "#/parameters/SourceUrl" + }, + { + "$ref": "#/parameters/SourceRange" + }, + { + "$ref": "#/parameters/SourceContentMD5" + }, + { + "$ref": "#/parameters/SourceContentCRC64" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/EncryptionKey" + }, + { + "$ref": "#/parameters/EncryptionKeySha256" + }, + { + "$ref": "#/parameters/EncryptionAlgorithm" + }, + { + "$ref": "#/parameters/EncryptionScope" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/SourceIfModifiedSince" + }, + { + "$ref": "#/parameters/SourceIfUnmodifiedSince" + }, + { + "$ref": "#/parameters/SourceIfMatch" + }, + { + "$ref": "#/parameters/SourceIfNoneMatch" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/CopySourceAuthorization" + } + ], + "responses": { + "201": { + "description": "The block was created.", + "headers": { + "Content-MD5": { + "type": "string", + "format": "byte", + "description": "This header is returned so that the client can check for message content integrity. The value of this header is computed by the Blob service; it is not necessarily the same value specified in the request headers." + }, + "x-ms-content-crc64": { + "type": "string", + "format": "byte", + "description": "This header is returned so that the client can check for message content integrity. The value of this header is computed by the Blob service; it is not necessarily the same value specified in the request headers." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-request-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the contents of the request are successfully encrypted using the specified algorithm, and false otherwise." + }, + "x-ms-encryption-key-sha256": { + "x-ms-client-name": "EncryptionKeySha256", + "type": "string", + "description": "The SHA-256 hash of the encryption key used to encrypt the block. This header is only returned when the block was encrypted with a customer-provided key." + }, + "x-ms-encryption-scope": { + "x-ms-client-name": "EncryptionScope", + "type": "string", + "description": "Returns the name of the encryption scope used to encrypt the blob contents and application metadata. Note that the absence of this header implies use of the default account encryption scope." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["block"] + } + ] + }, + "/{containerName}/{blob}?comp=blocklist": { + "put": { + "tags": ["blockblob"], + "operationId": "BlockBlob_CommitBlockList", + "description": "The Commit Block List operation writes a blob by specifying the list of block IDs that make up the blob. In order to be written as part of a blob, a block must have been successfully written to the server in a prior Put Block operation. You can call Put Block List to update a blob by uploading only those blocks that have changed, then committing the new and existing blocks together. You can do this by specifying whether to commit a block from the committed block list or from the uncommitted block list, or to commit the most recently uploaded version of the block, whichever list it may belong to.", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/BlobCacheControl" + }, + { + "$ref": "#/parameters/BlobContentType" + }, + { + "$ref": "#/parameters/BlobContentEncoding" + }, + { + "$ref": "#/parameters/BlobContentLanguage" + }, + { + "$ref": "#/parameters/BlobContentMD5" + }, + { + "$ref": "#/parameters/ContentMD5Blob" + }, + { + "$ref": "#/parameters/ContentCrc64" + }, + { + "$ref": "#/parameters/Metadata" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/BlobContentDisposition" + }, + { + "$ref": "#/parameters/EncryptionKey" + }, + { + "$ref": "#/parameters/EncryptionKeySha256" + }, + { + "$ref": "#/parameters/EncryptionAlgorithm" + }, + { + "$ref": "#/parameters/EncryptionScope" + }, + { + "$ref": "#/parameters/AccessTierOptional" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "name": "blocks", + "description": "Blob Blocks.", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/BlockLookupList" + } + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/BlobTagsHeader" + }, + { + "$ref": "#/parameters/ImmutabilityPolicyExpiry" + }, + { + "$ref": "#/parameters/ImmutabilityPolicyMode" + }, + { + "$ref": "#/parameters/LegalHoldOptional" + } + ], + "responses": { + "201": { + "description": "The block list was recorded.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "Content-MD5": { + "type": "string", + "format": "byte", + "description": "This header is returned so that the client can check for message content integrity. This header refers to the content of the request, meaning, in this case, the list of blocks, and not the content of the blob itself." + }, + "x-ms-content-crc64": { + "type": "string", + "format": "byte", + "description": "This header is returned so that the client can check for message content integrity. This header refers to the content of the request, meaning, in this case, the list of blocks, and not the content of the blob itself." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "x-ms-version-id": { + "x-ms-client-name": "VersionId", + "type": "string", + "description": "A DateTime value returned by the service that uniquely identifies the blob. The value of this header indicates the blob version, and may be used in subsequent requests to access this version of the blob." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-request-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the contents of the request are successfully encrypted using the specified algorithm, and false otherwise." + }, + "x-ms-encryption-key-sha256": { + "x-ms-client-name": "EncryptionKeySha256", + "type": "string", + "description": "The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned when the blob was encrypted with a customer-provided key." + }, + "x-ms-encryption-scope": { + "x-ms-client-name": "EncryptionScope", + "type": "string", + "description": "Returns the name of the encryption scope used to encrypt the blob contents and application metadata. Note that the absence of this header implies use of the default account encryption scope." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "get": { + "tags": ["blockblob"], + "operationId": "BlockBlob_GetBlockList", + "description": "The Get Block List operation retrieves the list of blocks that have been uploaded as part of a block blob", + "parameters": [ + { + "$ref": "#/parameters/Snapshot" + }, + { + "$ref": "#/parameters/BlockListType" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "The page range was written.", + "headers": { + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Content-Type": { + "type": "string", + "description": "The media type of the body of the response. For Get Block List this is 'application/xml'" + }, + "x-ms-blob-content-length": { + "x-ms-client-name": "BlobContentLength", + "type": "integer", + "format": "int64", + "description": "The size of the blob in bytes." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + }, + "schema": { + "$ref": "#/definitions/BlockList" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["blocklist"] + } + ] + }, + "/{containerName}/{blob}?comp=page&update": { + "put": { + "tags": ["pageblob"], + "operationId": "PageBlob_UploadPages", + "description": "The Upload Pages operation writes a range of pages to a page blob", + "consumes": ["application/octet-stream"], + "parameters": [ + { + "$ref": "#/parameters/Body" + }, + { + "$ref": "#/parameters/ContentLengthBlob" + }, + { + "$ref": "#/parameters/ContentMD5Blob" + }, + { + "$ref": "#/parameters/ContentCrc64" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/Range" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/EncryptionKey" + }, + { + "$ref": "#/parameters/EncryptionKeySha256" + }, + { + "$ref": "#/parameters/EncryptionAlgorithm" + }, + { + "$ref": "#/parameters/EncryptionScope" + }, + { + "$ref": "#/parameters/IfSequenceNumberLessThanOrEqualTo" + }, + { + "$ref": "#/parameters/IfSequenceNumberLessThan" + }, + { + "$ref": "#/parameters/IfSequenceNumberEqualTo" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "201": { + "description": "The page range was written.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "Content-MD5": { + "type": "string", + "format": "byte", + "description": "If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the client can check for message content integrity." + }, + "x-ms-content-crc64": { + "type": "string", + "format": "byte", + "description": "This header is returned so that the client can check for message content integrity. The value of this header is computed by the Blob service; it is not necessarily the same value specified in the request headers." + }, + "x-ms-blob-sequence-number": { + "x-ms-client-name": "BlobSequenceNumber", + "type": "integer", + "format": "int64", + "description": "The current sequence number for the page blob." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-request-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the contents of the request are successfully encrypted using the specified algorithm, and false otherwise." + }, + "x-ms-encryption-key-sha256": { + "x-ms-client-name": "EncryptionKeySha256", + "type": "string", + "description": "The SHA-256 hash of the encryption key used to encrypt the pages. This header is only returned when the pages were encrypted with a customer-provided key." + }, + "x-ms-encryption-scope": { + "x-ms-client-name": "EncryptionScope", + "type": "string", + "description": "Returns the name of the encryption scope used to encrypt the blob contents and application metadata. Note that the absence of this header implies use of the default account encryption scope." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["page"] + }, + { + "name": "x-ms-page-write", + "x-ms-client-name": "pageWrite", + "in": "header", + "required": true, + "x-ms-parameter-location": "method", + "description": "Required. You may specify one of the following options:\n - Update: Writes the bytes specified by the request body into the specified range. The Range and Content-Length headers must match to perform the update.\n - Clear: Clears the specified range and releases the space used in storage for that range. To clear a range, set the Content-Length header to zero, and the Range header to a value that indicates the range to clear, up to maximum blob size.", + "type": "string", + "enum": ["update"], + "x-ms-enum": { + "name": "PageWriteType", + "modelAsString": false + } + } + ] + }, + "/{containerName}/{blob}?comp=page&clear": { + "put": { + "tags": ["pageblob"], + "operationId": "PageBlob_ClearPages", + "description": "The Clear Pages operation clears a set of pages from a page blob", + "consumes": ["application/octet-stream"], + "parameters": [ + { + "$ref": "#/parameters/ContentLengthBlob" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/Range" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/EncryptionKey" + }, + { + "$ref": "#/parameters/EncryptionKeySha256" + }, + { + "$ref": "#/parameters/EncryptionAlgorithm" + }, + { + "$ref": "#/parameters/EncryptionScope" + }, + { + "$ref": "#/parameters/IfSequenceNumberLessThanOrEqualTo" + }, + { + "$ref": "#/parameters/IfSequenceNumberLessThan" + }, + { + "$ref": "#/parameters/IfSequenceNumberEqualTo" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "201": { + "description": "The page range was cleared.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "Content-MD5": { + "type": "string", + "format": "byte", + "description": "If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the client can check for message content integrity." + }, + "x-ms-content-crc64": { + "type": "string", + "format": "byte", + "description": "This header is returned so that the client can check for message content integrity. The value of this header is computed by the Blob service; it is not necessarily the same value specified in the request headers." + }, + "x-ms-blob-sequence-number": { + "x-ms-client-name": "BlobSequenceNumber", + "type": "integer", + "format": "int64", + "description": "The current sequence number for the page blob." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["page"] + }, + { + "name": "x-ms-page-write", + "x-ms-client-name": "pageWrite", + "in": "header", + "required": true, + "x-ms-parameter-location": "method", + "description": "Required. You may specify one of the following options:\n - Update: Writes the bytes specified by the request body into the specified range. The Range and Content-Length headers must match to perform the update.\n - Clear: Clears the specified range and releases the space used in storage for that range. To clear a range, set the Content-Length header to zero, and the Range header to a value that indicates the range to clear, up to maximum blob size.", + "type": "string", + "enum": ["clear"], + "x-ms-enum": { + "name": "PageWriteType", + "modelAsString": false + } + } + ] + }, + "/{containerName}/{blob}?comp=page&update&fromUrl": { + "put": { + "tags": ["pageblob"], + "operationId": "PageBlob_UploadPagesFromURL", + "description": "The Upload Pages operation writes a range of pages to a page blob where the contents are read from a URL", + "consumes": ["application/octet-stream"], + "parameters": [ + { + "$ref": "#/parameters/SourceUrl" + }, + { + "$ref": "#/parameters/SourceRangeRequiredPutPageFromUrl" + }, + { + "$ref": "#/parameters/SourceContentMD5" + }, + { + "$ref": "#/parameters/SourceContentCRC64" + }, + { + "$ref": "#/parameters/ContentLengthBlob" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/RangeRequiredPutPageFromUrl" + }, + { + "$ref": "#/parameters/EncryptionKey" + }, + { + "$ref": "#/parameters/EncryptionKeySha256" + }, + { + "$ref": "#/parameters/EncryptionAlgorithm" + }, + { + "$ref": "#/parameters/EncryptionScope" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/IfSequenceNumberLessThanOrEqualTo" + }, + { + "$ref": "#/parameters/IfSequenceNumberLessThan" + }, + { + "$ref": "#/parameters/IfSequenceNumberEqualTo" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/SourceIfModifiedSince" + }, + { + "$ref": "#/parameters/SourceIfUnmodifiedSince" + }, + { + "$ref": "#/parameters/SourceIfMatch" + }, + { + "$ref": "#/parameters/SourceIfNoneMatch" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/CopySourceAuthorization" + } + ], + "responses": { + "201": { + "description": "The page range was written.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "Content-MD5": { + "type": "string", + "format": "byte", + "description": "If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the client can check for message content integrity." + }, + "x-ms-content-crc64": { + "type": "string", + "format": "byte", + "description": "This header is returned so that the client can check for message content integrity. The value of this header is computed by the Blob service; it is not necessarily the same value specified in the request headers." + }, + "x-ms-blob-sequence-number": { + "x-ms-client-name": "BlobSequenceNumber", + "type": "integer", + "format": "int64", + "description": "The current sequence number for the page blob." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-request-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the contents of the request are successfully encrypted using the specified algorithm, and false otherwise." + }, + "x-ms-encryption-key-sha256": { + "x-ms-client-name": "EncryptionKeySha256", + "type": "string", + "description": "The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned when the blob was encrypted with a customer-provided key." + }, + "x-ms-encryption-scope": { + "x-ms-client-name": "EncryptionScope", + "type": "string", + "description": "Returns the name of the encryption scope used to encrypt the blob contents and application metadata. Note that the absence of this header implies use of the default account encryption scope." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "page" + ] + }, + { + "name": "x-ms-page-write", + "x-ms-client-name": "pageWrite", + "in": "header", + "required": true, + "x-ms-parameter-location": "method", + "description": "Required. You may specify one of the following options:\n - Update: Writes the bytes specified by the request body into the specified range. The Range and Content-Length headers must match to perform the update.\n - Clear: Clears the specified range and releases the space used in storage for that range. To clear a range, set the Content-Length header to zero, and the Range header to a value that indicates the range to clear, up to maximum blob size.", + "type": "string", + "enum": [ + "update" + ], + "x-ms-enum": { + "name": "PageWriteType", + "modelAsString": false + } + } + ] + }, + "/{containerName}/{blob}?comp=pagelist": { + "get": { + "tags": [ + "pageblob" + ], + "operationId": "PageBlob_GetPageRanges", + "description": "The Get Page Ranges operation returns the list of valid page ranges for a page blob or snapshot of a page blob", + "parameters": [ + { + "$ref": "#/parameters/Snapshot" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/Range" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/Marker" + }, + { + "$ref": "#/parameters/MaxResultsBlob" + } + ], + "responses": { + "200": { + "description": "Information on the page blob was found.", + "headers": { + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "x-ms-blob-content-length": { + "x-ms-client-name": "BlobContentLength", + "type": "integer", + "format": "int64", + "description": "The size of the blob in bytes." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + }, + "schema": { + "$ref": "#/definitions/PageList" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "NextMarker" + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "pagelist" + ] + } + ] + }, + "/{containerName}/{blob}?comp=pagelist&diff": { + "get": { + "tags": [ + "pageblob" + ], + "operationId": "PageBlob_GetPageRangesDiff", + "description": "The Get Page Ranges Diff operation returns the list of valid page ranges for a page blob that were changed between target blob and previous snapshot.", + "parameters": [ + { + "$ref": "#/parameters/Snapshot" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/PrevSnapshot" + }, + { + "$ref": "#/parameters/PrevSnapshotUrl" + }, + { + "$ref": "#/parameters/Range" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/Marker" + }, + { + "$ref": "#/parameters/MaxResultsBlob" + } + ], + "responses": { + "200": { + "description": "Information on the page blob was found.", + "headers": { + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "x-ms-blob-content-length": { + "x-ms-client-name": "BlobContentLength", + "type": "integer", + "format": "int64", + "description": "The size of the blob in bytes." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + }, + "schema": { + "$ref": "#/definitions/PageList" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "NextMarker" + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "pagelist" + ] + } + ] + }, + "/{containerName}/{blob}?comp=properties&Resize": { + "put": { + "tags": [ + "pageblob" + ], + "operationId": "PageBlob_Resize", + "description": "Resize the Blob", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/EncryptionKey" + }, + { + "$ref": "#/parameters/EncryptionKeySha256" + }, + { + "$ref": "#/parameters/EncryptionAlgorithm" + }, + { + "$ref": "#/parameters/EncryptionScope" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/BlobContentLengthRequired" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "The Blob was resized successfully", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-blob-sequence-number": { + "x-ms-client-name": "BlobSequenceNumber", + "type": "integer", + "format": "int64", + "description": "The current sequence number for a page blob. This header is not returned for block blobs or append blobs" + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "properties" + ] + } + ] + }, + "/{containerName}/{blob}?comp=properties&UpdateSequenceNumber": { + "put": { + "tags": [ + "pageblob" + ], + "operationId": "PageBlob_UpdateSequenceNumber", + "description": "Update the sequence number of the blob", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/SequenceNumberAction" + }, + { + "$ref": "#/parameters/BlobSequenceNumber" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "The sequence numbers were updated successfully.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-blob-sequence-number": { + "x-ms-client-name": "BlobSequenceNumber", + "type": "integer", + "format": "int64", + "description": "The current sequence number for a page blob. This header is not returned for block blobs or append blobs" + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "properties" + ] + } + ] + }, + "/{containerName}/{blob}?comp=incrementalcopy": { + "put": { + "tags": [ + "pageblob" + ], + "operationId": "PageBlob_CopyIncremental", + "description": "The Copy Incremental operation copies a snapshot of the source page blob to a destination page blob. The snapshot is copied such that only the differential changes between the previously copied snapshot are transferred to the destination. The copied snapshots are complete copies of the original snapshot and can be read or copied from as usual. This API is supported since REST version 2016-05-31.", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/CopySource" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "202": { + "description": "The blob was copied.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-copy-id": { + "x-ms-client-name": "CopyId", + "type": "string", + "description": "String identifier for this copy operation. Use with Get Blob Properties to check the status of this copy operation, or pass to Abort Copy Blob to abort a pending copy." + }, + "x-ms-copy-status": { + "x-ms-client-name": "CopyStatus", + "description": "State of the copy operation identified by x-ms-copy-id.", + "type": "string", + "enum": [ + "pending", + "success", + "aborted", + "failed" + ], + "x-ms-enum": { + "name": "CopyStatusType", + "modelAsString": false + } + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "incrementalcopy" + ] + } + ] + }, + "/{containerName}/{blob}?comp=appendblock": { + "put": { + "tags": [ + "appendblob" + ], + "consumes": [ + "application/octet-stream" + ], + "operationId": "AppendBlob_AppendBlock", + "description": "The Append Block operation commits a new block of data to the end of an existing append blob. The Append Block operation is permitted only if the blob was created with x-ms-blob-type set to AppendBlob. Append Block is supported only on version 2015-02-21 version or later.", + "parameters": [ + { + "$ref": "#/parameters/Body" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ContentLengthBlob" + }, + { + "$ref": "#/parameters/ContentMD5Blob" + }, + { + "$ref": "#/parameters/ContentCrc64" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/BlobConditionMaxSize" + }, + { + "$ref": "#/parameters/BlobConditionAppendPos" + }, + { + "$ref": "#/parameters/EncryptionKey" + }, + { + "$ref": "#/parameters/EncryptionKeySha256" + }, + { + "$ref": "#/parameters/EncryptionAlgorithm" + }, + { + "$ref": "#/parameters/EncryptionScope" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "201": { + "description": "The block was created.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "Content-MD5": { + "type": "string", + "format": "byte", + "description": "If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the client can check for message content integrity." + }, + "x-ms-content-crc64": { + "type": "string", + "format": "byte", + "description": "This header is returned so that the client can check for message content integrity. The value of this header is computed by the Blob service; it is not necessarily the same value specified in the request headers." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-blob-append-offset": { + "x-ms-client-name": "BlobAppendOffset", + "type": "string", + "description": "This response header is returned only for append operations. It returns the offset at which the block was committed, in bytes." + }, + "x-ms-blob-committed-block-count": { + "x-ms-client-name": "BlobCommittedBlockCount", + "type": "integer", + "description": "The number of committed blocks present in the blob. This header is returned only for append blobs." + }, + "x-ms-request-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the contents of the request are successfully encrypted using the specified algorithm, and false otherwise." + }, + "x-ms-encryption-key-sha256": { + "x-ms-client-name": "EncryptionKeySha256", + "type": "string", + "description": "The SHA-256 hash of the encryption key used to encrypt the block. This header is only returned when the block was encrypted with a customer-provided key." + }, + "x-ms-encryption-scope": { + "x-ms-client-name": "EncryptionScope", + "type": "string", + "description": "Returns the name of the encryption scope used to encrypt the blob contents and application metadata. Note that the absence of this header implies use of the default account encryption scope." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "appendblock" + ] + } + ] + }, + "/{containerName}/{blob}?comp=appendblock&fromUrl": { + "put": { + "tags": [ + "appendblob" + ], + "operationId": "AppendBlob_AppendBlockFromUrl", + "description": "The Append Block operation commits a new block of data to the end of an existing append blob where the contents are read from a source url. The Append Block operation is permitted only if the blob was created with x-ms-blob-type set to AppendBlob. Append Block is supported only on version 2015-02-21 version or later.", + "parameters": [ + { + "$ref": "#/parameters/SourceUrl" + }, + { + "$ref": "#/parameters/SourceRange" + }, + { + "$ref": "#/parameters/SourceContentMD5" + }, + { + "$ref": "#/parameters/SourceContentCRC64" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ContentLengthBlob" + }, + { + "$ref": "#/parameters/ContentMD5Blob" + }, + { + "$ref": "#/parameters/EncryptionKey" + }, + { + "$ref": "#/parameters/EncryptionKeySha256" + }, + { + "$ref": "#/parameters/EncryptionAlgorithm" + }, + { + "$ref": "#/parameters/EncryptionScope" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/BlobConditionMaxSize" + }, + { + "$ref": "#/parameters/BlobConditionAppendPos" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/SourceIfModifiedSince" + }, + { + "$ref": "#/parameters/SourceIfUnmodifiedSince" + }, + { + "$ref": "#/parameters/SourceIfMatch" + }, + { + "$ref": "#/parameters/SourceIfNoneMatch" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/CopySourceAuthorization" + } + ], + "responses": { + "201": { + "description": "The block was created.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "Content-MD5": { + "type": "string", + "format": "byte", + "description": "If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the client can check for message content integrity." + }, + "x-ms-content-crc64": { + "type": "string", + "format": "byte", + "description": "This header is returned so that the client can check for message content integrity. The value of this header is computed by the Blob service; it is not necessarily the same value specified in the request headers." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-blob-append-offset": { + "x-ms-client-name": "BlobAppendOffset", + "type": "string", + "description": "This response header is returned only for append operations. It returns the offset at which the block was committed, in bytes." + }, + "x-ms-blob-committed-block-count": { + "x-ms-client-name": "BlobCommittedBlockCount", + "type": "integer", + "description": "The number of committed blocks present in the blob. This header is returned only for append blobs." + }, + "x-ms-encryption-key-sha256": { + "x-ms-client-name": "EncryptionKeySha256", + "type": "string", + "description": "The SHA-256 hash of the encryption key used to encrypt the block. This header is only returned when the block was encrypted with a customer-provided key." + }, + "x-ms-encryption-scope": { + "x-ms-client-name": "EncryptionScope", + "type": "string", + "description": "Returns the name of the encryption scope used to encrypt the blob contents and application metadata. Note that the absence of this header implies use of the default account encryption scope." + }, + "x-ms-request-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the contents of the request are successfully encrypted using the specified algorithm, and false otherwise." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "appendblock" + ] + } + ] + }, + "/{containerName}/{blob}?comp=seal": { + "put": { + "tags": [ + "appendblob" + ], + "operationId": "AppendBlob_Seal", + "description": "The Seal operation seals the Append Blob to make it read-only. Seal is supported only on version 2019-12-12 version or later.", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/BlobConditionAppendPos" + } + ], + "responses": { + "200": { + "description": "The blob was sealed.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-blob-sealed": { + "x-ms-client-name": "IsSealed", + "type": "boolean", + "description": "If this blob has been sealed" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "seal" + ] + } + ] + }, + "/{containerName}/{blob}?comp=query": { + "post": { + "tags": [ + "blob" + ], + "operationId": "Blob_Query", + "description": "The Query operation enables users to select/project on blob data by providing simple query expressions.", + "parameters": [ + { + "$ref": "#/parameters/QueryRequest" + }, + { + "$ref": "#/parameters/Snapshot" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/EncryptionKey" + }, + { + "$ref": "#/parameters/EncryptionKeySha256" + }, + { + "$ref": "#/parameters/EncryptionAlgorithm" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "Returns the content of the entire blob.", + "headers": { + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-meta": { + "type": "string", + "x-ms-client-name": "Metadata", + "x-ms-header-collection-prefix": "x-ms-meta-" + }, + "Content-Length": { + "type": "integer", + "format": "int64", + "description": "The number of bytes present in the response body." + }, + "Content-Type": { + "type": "string", + "description": "The media type of the body of the response. For Download Blob this is 'application/octet-stream'" + }, + "Content-Range": { + "type": "string", + "description": "Indicates the range of bytes returned in the event that the client requested a subset of the blob by setting the 'Range' request header." + }, + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Content-MD5": { + "type": "string", + "format": "byte", + "description": "If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the client can check for message content integrity." + }, + "Content-Encoding": { + "type": "string", + "description": "This header returns the value that was specified for the Content-Encoding request header" + }, + "Cache-Control": { + "type": "string", + "description": "This header is returned if it was previously specified for the blob." + }, + "Content-Disposition": { + "type": "string", + "description": "This header returns the value that was specified for the 'x-ms-blob-content-disposition' header. The Content-Disposition response header field conveys additional information about how to process the response payload, and also can be used to attach additional metadata. For example, if set to attachment, it indicates that the user-agent should not display the response, but instead show a Save As dialog with a filename other than the blob name specified." + }, + "Content-Language": { + "type": "string", + "description": "This header returns the value that was specified for the Content-Language request header." + }, + "x-ms-blob-sequence-number": { + "x-ms-client-name": "BlobSequenceNumber", + "type": "integer", + "format": "int64", + "description": "The current sequence number for a page blob. This header is not returned for block blobs or append blobs" + }, + "x-ms-blob-type": { + "x-ms-client-name": "BlobType", + "description": "The blob's type.", + "type": "string", + "enum": [ + "BlockBlob", + "PageBlob", + "AppendBlob" + ], + "x-ms-enum": { + "name": "BlobType", + "modelAsString": false + } + }, + "x-ms-copy-completion-time": { + "x-ms-client-name": "CopyCompletionTime", + "type": "string", + "format": "date-time-rfc1123", + "description": "Conclusion time of the last attempted Copy Blob operation where this blob was the destination blob. This value can specify the time of a completed, aborted, or failed copy attempt. This header does not appear if a copy is pending, if this blob has never been the destination in a Copy Blob operation, or if this blob has been modified after a concluded Copy Blob operation using Set Blob Properties, Put Blob, or Put Block List." + }, + "x-ms-copy-status-description": { + "x-ms-client-name": "CopyStatusDescription", + "type": "string", + "description": "Only appears when x-ms-copy-status is failed or pending. Describes the cause of the last fatal or non-fatal copy operation failure. This header does not appear if this blob has never been the destination in a Copy Blob operation, or if this blob has been modified after a concluded Copy Blob operation using Set Blob Properties, Put Blob, or Put Block List" + }, + "x-ms-copy-id": { + "x-ms-client-name": "CopyId", + "type": "string", + "description": "String identifier for this copy operation. Use with Get Blob Properties to check the status of this copy operation, or pass to Abort Copy Blob to abort a pending copy." + }, + "x-ms-copy-progress": { + "x-ms-client-name": "CopyProgress", + "type": "string", + "description": "Contains the number of bytes copied and the total bytes in the source in the last attempted Copy Blob operation where this blob was the destination blob. Can show between 0 and Content-Length bytes copied. This header does not appear if this blob has never been the destination in a Copy Blob operation, or if this blob has been modified after a concluded Copy Blob operation using Set Blob Properties, Put Blob, or Put Block List" + }, + "x-ms-copy-source": { + "x-ms-client-name": "CopySource", + "type": "string", + "description": "URL up to 2 KB in length that specifies the source blob or file used in the last attempted Copy Blob operation where this blob was the destination blob. This header does not appear if this blob has never been the destination in a Copy Blob operation, or if this blob has been modified after a concluded Copy Blob operation using Set Blob Properties, Put Blob, or Put Block List." + }, + "x-ms-copy-status": { + "x-ms-client-name": "CopyStatus", + "description": "State of the copy operation identified by x-ms-copy-id.", + "type": "string", + "enum": [ + "pending", + "success", + "aborted", + "failed" + ], + "x-ms-enum": { + "name": "CopyStatusType", + "modelAsString": false + } + }, + "x-ms-lease-duration": { + "x-ms-client-name": "LeaseDuration", + "description": "When a blob is leased, specifies whether the lease is of infinite or fixed duration.", + "type": "string", + "enum": [ + "infinite", + "fixed" + ], + "x-ms-enum": { + "name": "LeaseDurationType", + "modelAsString": false + } + }, + "x-ms-lease-state": { + "x-ms-client-name": "LeaseState", + "description": "Lease state of the blob.", + "type": "string", + "enum": [ + "available", + "leased", + "expired", + "breaking", + "broken" + ], + "x-ms-enum": { + "name": "LeaseStateType", + "modelAsString": false + } + }, + "x-ms-lease-status": { + "x-ms-client-name": "LeaseStatus", + "description": "The current lease status of the blob.", + "type": "string", + "enum": [ + "locked", + "unlocked" + ], + "x-ms-enum": { + "name": "LeaseStatusType", + "modelAsString": false + } + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Accept-Ranges": { + "type": "string", + "description": "Indicates that the service supports requests for partial blob content." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-blob-committed-block-count": { + "x-ms-client-name": "BlobCommittedBlockCount", + "type": "integer", + "description": "The number of committed blocks present in the blob. This header is returned only for append blobs." + }, + "x-ms-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the blob data and application metadata are completely encrypted using the specified algorithm. Otherwise, the value is set to false (when the blob is unencrypted, or if only parts of the blob/application metadata are encrypted)." + }, + "x-ms-encryption-key-sha256": { + "x-ms-client-name": "EncryptionKeySha256", + "type": "string", + "description": "The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned when the blob was encrypted with a customer-provided key." + }, + "x-ms-encryption-scope": { + "x-ms-client-name": "EncryptionScope", + "type": "string", + "description": "Returns the name of the encryption scope used to encrypt the blob contents and application metadata. Note that the absence of this header implies use of the default account encryption scope." + }, + "x-ms-blob-content-md5": { + "x-ms-client-name": "BlobContentMD5", + "type": "string", + "format": "byte", + "description": "If the blob has a MD5 hash, and if request contains range header (Range or x-ms-range), this response header is returned with the value of the whole blob's MD5 value. This value may or may not be equal to the value returned in Content-MD5 header, with the latter calculated from the requested range" + } + }, + "schema": { + "type": "object", + "format": "file" + } + }, + "206": { + "description": "Returns the content of a specified range of the blob.", + "headers": { + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-meta": { + "type": "string", + "x-ms-client-name": "Metadata", + "x-ms-header-collection-prefix": "x-ms-meta-" + }, + "Content-Length": { + "type": "integer", + "format": "int64", + "description": "The number of bytes present in the response body." + }, + "Content-Type": { + "type": "string", + "description": "The media type of the body of the response. For Download Blob this is 'application/octet-stream'" + }, + "Content-Range": { + "type": "string", + "description": "Indicates the range of bytes returned in the event that the client requested a subset of the blob by setting the 'Range' request header." + }, + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Content-MD5": { + "type": "string", + "format": "byte", + "description": "If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the client can check for message content integrity." + }, + "Content-Encoding": { + "type": "string", + "description": "This header returns the value that was specified for the Content-Encoding request header" + }, + "Cache-Control": { + "type": "string", + "description": "This header is returned if it was previously specified for the blob." + }, + "Content-Disposition": { + "type": "string", + "description": "This header returns the value that was specified for the 'x-ms-blob-content-disposition' header. The Content-Disposition response header field conveys additional information about how to process the response payload, and also can be used to attach additional metadata. For example, if set to attachment, it indicates that the user-agent should not display the response, but instead show a Save As dialog with a filename other than the blob name specified." + }, + "Content-Language": { + "type": "string", + "description": "This header returns the value that was specified for the Content-Language request header." + }, + "x-ms-blob-sequence-number": { + "x-ms-client-name": "BlobSequenceNumber", + "type": "integer", + "format": "int64", + "description": "The current sequence number for a page blob. This header is not returned for block blobs or append blobs" + }, + "x-ms-blob-type": { + "x-ms-client-name": "BlobType", + "description": "The blob's type.", + "type": "string", + "enum": [ + "BlockBlob", + "PageBlob", + "AppendBlob" + ], + "x-ms-enum": { + "name": "BlobType", + "modelAsString": false + } + }, + "x-ms-content-crc64": { + "x-ms-client-name": "ContentCrc64", + "type": "string", + "format": "byte", + "description": "If the request is to read a specified range and the x-ms-range-get-content-crc64 is set to true, then the request returns a crc64 for the range, as long as the range size is less than or equal to 4 MB. If both x-ms-range-get-content-crc64 and x-ms-range-get-content-md5 is specified in the same request, it will fail with 400(Bad Request)" + }, + "x-ms-copy-completion-time": { + "x-ms-client-name": "CopyCompletionTime", + "type": "string", + "format": "date-time-rfc1123", + "description": "Conclusion time of the last attempted Copy Blob operation where this blob was the destination blob. This value can specify the time of a completed, aborted, or failed copy attempt. This header does not appear if a copy is pending, if this blob has never been the destination in a Copy Blob operation, or if this blob has been modified after a concluded Copy Blob operation using Set Blob Properties, Put Blob, or Put Block List." + }, + "x-ms-copy-status-description": { + "x-ms-client-name": "CopyStatusDescription", + "type": "string", + "description": "Only appears when x-ms-copy-status is failed or pending. Describes the cause of the last fatal or non-fatal copy operation failure. This header does not appear if this blob has never been the destination in a Copy Blob operation, or if this blob has been modified after a concluded Copy Blob operation using Set Blob Properties, Put Blob, or Put Block List" + }, + "x-ms-copy-id": { + "x-ms-client-name": "CopyId", + "type": "string", + "description": "String identifier for this copy operation. Use with Get Blob Properties to check the status of this copy operation, or pass to Abort Copy Blob to abort a pending copy." + }, + "x-ms-copy-progress": { + "x-ms-client-name": "CopyProgress", + "type": "string", + "description": "Contains the number of bytes copied and the total bytes in the source in the last attempted Copy Blob operation where this blob was the destination blob. Can show between 0 and Content-Length bytes copied. This header does not appear if this blob has never been the destination in a Copy Blob operation, or if this blob has been modified after a concluded Copy Blob operation using Set Blob Properties, Put Blob, or Put Block List" + }, + "x-ms-copy-source": { + "x-ms-client-name": "CopySource", + "type": "string", + "description": "URL up to 2 KB in length that specifies the source blob or file used in the last attempted Copy Blob operation where this blob was the destination blob. This header does not appear if this blob has never been the destination in a Copy Blob operation, or if this blob has been modified after a concluded Copy Blob operation using Set Blob Properties, Put Blob, or Put Block List." + }, + "x-ms-copy-status": { + "x-ms-client-name": "CopyStatus", + "description": "State of the copy operation identified by x-ms-copy-id.", + "type": "string", + "enum": [ + "pending", + "success", + "aborted", + "failed" + ], + "x-ms-enum": { + "name": "CopyStatusType", + "modelAsString": false + } + }, + "x-ms-lease-duration": { + "x-ms-client-name": "LeaseDuration", + "description": "When a blob is leased, specifies whether the lease is of infinite or fixed duration.", + "type": "string", + "enum": [ + "infinite", + "fixed" + ], + "x-ms-enum": { + "name": "LeaseDurationType", + "modelAsString": false + } + }, + "x-ms-lease-state": { + "x-ms-client-name": "LeaseState", + "description": "Lease state of the blob.", + "type": "string", + "enum": [ + "available", + "leased", + "expired", + "breaking", + "broken" + ], + "x-ms-enum": { + "name": "LeaseStateType", + "modelAsString": false + } + }, + "x-ms-lease-status": { + "x-ms-client-name": "LeaseStatus", + "description": "The current lease status of the blob.", + "type": "string", + "enum": [ + "locked", + "unlocked" + ], + "x-ms-enum": { + "name": "LeaseStatusType", + "modelAsString": false + } + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Accept-Ranges": { + "type": "string", + "description": "Indicates that the service supports requests for partial blob content." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + }, + "x-ms-blob-committed-block-count": { + "x-ms-client-name": "BlobCommittedBlockCount", + "type": "integer", + "description": "The number of committed blocks present in the blob. This header is returned only for append blobs." + }, + "x-ms-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the blob data and application metadata are completely encrypted using the specified algorithm. Otherwise, the value is set to false (when the blob is unencrypted, or if only parts of the blob/application metadata are encrypted)." + }, + "x-ms-encryption-key-sha256": { + "x-ms-client-name": "EncryptionKeySha256", + "type": "string", + "description": "The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned when the blob was encrypted with a customer-provided key." + }, + "x-ms-encryption-scope": { + "x-ms-client-name": "EncryptionScope", + "type": "string", + "description": "Returns the name of the encryption scope used to encrypt the blob contents and application metadata. Note that the absence of this header implies use of the default account encryption scope." + }, + "x-ms-blob-content-md5": { + "x-ms-client-name": "BlobContentMD5", + "type": "string", + "format": "byte", + "description": "If the blob has a MD5 hash, and if request contains range header (Range or x-ms-range), this response header is returned with the value of the whole blob's MD5 value. This value may or may not be equal to the value returned in Content-MD5 header, with the latter calculated from the requested range" + } + }, + "schema": { + "type": "object", + "format": "file" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "query" + ] + } + ] + }, + "/{containerName}/{blob}?comp=tags": { + "get": { + "tags": [ + "blob" + ], + "operationId": "Blob_GetTags", + "description": "The Get Tags operation enables users to get the tags associated with a blob.", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/Snapshot" + }, + { + "$ref": "#/parameters/VersionId" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + } + ], + "responses": { + "200": { + "description": "Retrieved blob tags", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + }, + "schema": { + "$ref": "#/definitions/BlobTags" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "put": { + "tags": [ + "blob" + ], + "operationId": "Blob_SetTags", + "description": "The Set Tags operation enables users to set tags on a blob.", + "parameters": [ + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/VersionId" + }, + { + "$ref": "#/parameters/ContentMD5Blob" + }, + { + "$ref": "#/parameters/ContentCrc64" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/BlobTagsBody" + } + ], + "responses": { + "204": { + "description": "The tags were applied to the blob", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "tags" + ] + } + ] + } + }, + "definitions": { + "KeyInfo": { + "type": "object", + "required": [ + "Start", + "Expiry" + ], + "description": "Key information", + "properties": { + "Start": { + "description": "The date-time the key is active in ISO 8601 UTC time", + "type": "string" + }, + "Expiry": { + "description": "The date-time the key expires in ISO 8601 UTC time", + "type": "string" + } + } + }, + "UserDelegationKey": { + "type": "object", + "required": [ + "SignedOid", + "SignedTid", + "SignedStart", + "SignedExpiry", + "SignedService", + "SignedVersion", + "Value" + ], + "description": "A user delegation key", + "properties": { + "SignedOid": { + "description": "The Azure Active Directory object ID in GUID format.", + "type": "string" + }, + "SignedTid": { + "description": "The Azure Active Directory tenant ID in GUID format", + "type": "string" + }, + "SignedStart": { + "description": "The date-time the key is active", + "type": "string", + "format": "date-time" + }, + "SignedExpiry": { + "description": "The date-time the key expires", + "type": "string", + "format": "date-time" + }, + "SignedService": { + "description": "Abbreviation of the Azure Storage service that accepts the key", + "type": "string" + }, + "SignedVersion": { + "description": "The service version that created the key", + "type": "string" + }, + "Value": { + "description": "The key as a base64 string", + "type": "string" + } + } + }, + "PublicAccessType": { + "type": "string", + "enum": [ + "container", + "blob" + ], + "x-ms-enum": { + "name": "PublicAccessType", + "modelAsString": true + } + }, + "CopyStatus": { + "type": "string", + "enum": [ + "pending", + "success", + "aborted", + "failed" + ], + "x-ms-enum": { + "name": "CopyStatusType", + "modelAsString": false + } + }, + "LeaseDuration": { + "type": "string", + "enum": [ + "infinite", + "fixed" + ], + "x-ms-enum": { + "name": "LeaseDurationType", + "modelAsString": false + } + }, + "LeaseState": { + "type": "string", + "enum": [ + "available", + "leased", + "expired", + "breaking", + "broken" + ], + "x-ms-enum": { + "name": "LeaseStateType", + "modelAsString": false + } + }, + "LeaseStatus": { + "type": "string", + "enum": [ + "locked", + "unlocked" + ], + "x-ms-enum": { + "name": "LeaseStatusType", + "modelAsString": false + } + }, + "StorageError": { + "type": "object", + "properties": { + "Message": { + "description": "The service error message.", + "type": "string" + }, + "error": { + "type": "object", + "description": "The service error response object.", + "properties": { + "Code": { + "description": "The service error code.", + "type": "string" + }, + "Message": { + "description": "The service error message.", + "type": "string" + } + } + } + } + }, + "AccessPolicy": { + "type": "object", + "description": "An Access policy", + "properties": { + "Start": { + "description": "the date-time the policy is active", + "type": "string", + "format": "date-time" + }, + "Expiry": { + "description": "the date-time the policy expires", + "type": "string", + "format": "date-time" + }, + "Permission": { + "description": "the permissions for the acl policy", + "type": "string" + } + } + }, + "AccessTier": { + "type": "string", + "enum": [ + "P4", + "P6", + "P10", + "P15", + "P20", + "P30", + "P40", + "P50", + "P60", + "P70", + "P80", + "Hot", + "Cool", + "Archive", + "Premium" + ], + "x-ms-enum": { + "name": "AccessTier", + "modelAsString": true + } + }, + "ArchiveStatus": { + "type": "string", + "enum": [ + "rehydrate-pending-to-hot", + "rehydrate-pending-to-cool" + ], + "x-ms-enum": { + "name": "ArchiveStatus", + "modelAsString": true + } + }, + "BlobItemInternal": { + "xml": { + "name": "Blob" + }, + "description": "An Azure Storage blob", + "type": "object", + "required": [ + "Name", + "Properties" + ], + "properties": { + "Name": { + "type": "string" + }, + "Deleted": { + "type": "boolean" + }, + "Snapshot": { + "type": "string" + }, + "VersionId": { + "type": "string" + }, + "IsCurrentVersion": { + "type": "boolean" + }, + "Properties": { + "$ref": "#/definitions/BlobPropertiesInternal" + }, + "Metadata": { + "$ref": "#/definitions/BlobMetadata" + }, + "BlobTags": { + "$ref": "#/definitions/BlobTags" + }, + "ObjectReplicationMetadata": { + "$ref": "#/definitions/ObjectReplicationMetadata" + }, + "HasVersionsOnly": { + "type": "boolean" + }, + "DeletionId": { + "type": "string" + } + } + }, + "BlobPropertiesInternal": { + "xml": { + "name": "Properties" + }, + "description": "Properties of a blob", + "type": "object", + "required": [ + "Etag", + "Last-Modified" + ], + "properties": { + "Creation-Time": { + "type": "string", + "format": "date-time-rfc1123" + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123" + }, + "Etag": { + "type": "string" + }, + "Content-Length": { + "type": "integer", + "format": "int64", + "description": "Size in bytes" + }, + "Content-Type": { + "type": "string" + }, + "Content-Encoding": { + "type": "string" + }, + "Content-Language": { + "type": "string" + }, + "Content-MD5": { + "type": "string", + "format": "byte" + }, + "Content-Disposition": { + "type": "string" + }, + "Cache-Control": { + "type": "string" + }, + "x-ms-blob-sequence-number": { + "x-ms-client-name": "blobSequenceNumber", + "type": "integer", + "format": "int64" + }, + "BlobType": { + "type": "string", + "enum": [ + "BlockBlob", + "PageBlob", + "AppendBlob" + ], + "x-ms-enum": { + "name": "BlobType", + "modelAsString": false + } + }, + "LeaseStatus": { + "$ref": "#/definitions/LeaseStatus" + }, + "LeaseState": { + "$ref": "#/definitions/LeaseState" + }, + "LeaseDuration": { + "$ref": "#/definitions/LeaseDuration" + }, + "CopyId": { + "type": "string" + }, + "CopyStatus": { + "$ref": "#/definitions/CopyStatus" + }, + "CopySource": { + "type": "string" + }, + "CopyProgress": { + "type": "string" + }, + "CopyCompletionTime": { + "type": "string", + "format": "date-time-rfc1123" + }, + "CopyStatusDescription": { + "type": "string" + }, + "ServerEncrypted": { + "type": "boolean" + }, + "IncrementalCopy": { + "type": "boolean" + }, + "DestinationSnapshot": { + "type": "string" + }, + "DeletedTime": { + "type": "string", + "format": "date-time-rfc1123" + }, + "RemainingRetentionDays": { + "type": "integer" + }, + "AccessTier": { + "$ref": "#/definitions/AccessTier" + }, + "AccessTierInferred": { + "type": "boolean" + }, + "ArchiveStatus": { + "$ref": "#/definitions/ArchiveStatus" + }, + "CustomerProvidedKeySha256": { + "type": "string" + }, + "EncryptionScope": { + "type": "string", + "description": "The name of the encryption scope under which the blob is encrypted." + }, + "AccessTierChangeTime": { + "type": "string", + "format": "date-time-rfc1123" + }, + "TagCount": { + "type": "integer" + }, + "Expiry-Time": { + "x-ms-client-name": "ExpiresOn", + "type": "string", + "format": "date-time-rfc1123" + }, + "Sealed": { + "x-ms-client-name": "IsSealed", + "type": "boolean" + }, + "RehydratePriority": { + "$ref": "#/definitions/RehydratePriority" + }, + "LastAccessTime": { + "x-ms-client-name": "LastAccessedOn", + "type": "string", + "format": "date-time-rfc1123" + }, + "ImmutabilityPolicyUntilDate": { + "x-ms-client-name": "ImmutabilityPolicyExpiresOn", + "type": "string", + "format": "date-time-rfc1123" + }, + "ImmutabilityPolicyMode": { + "type": "string", + "enum": [ + "Mutable", + "Unlocked", + "Locked" + ], + "x-ms-enum": { + "name": "BlobImmutabilityPolicyMode", + "modelAsString": false + } + }, + "LegalHold": { + "type": "boolean" + }, + "DeleteTime": { + "type": "string", + "format": "date-time-rfc1123" + }, + "properties": { + "type": "string" + } + } + }, + "ListBlobsHierarchySegmentResponse": { + "xml": { + "name": "EnumerationResults" + }, + "description": "An enumeration of blobs", + "type": "object", + "required": [ + "ServiceEndpoint", + "ContainerName", + "Segment" + ], + "properties": { + "ServiceEndpoint": { + "type": "string", + "xml": { + "attribute": true + } + }, + "ContainerName": { + "type": "string", + "xml": { + "attribute": true + } + }, + "Prefix": { + "type": "string" + }, + "Marker": { + "type": "string" + }, + "MaxResults": { + "type": "integer" + }, + "Delimiter": { + "type": "string" + }, + "Segment": { + "$ref": "#/definitions/BlobHierarchyListSegment" + }, + "NextMarker": { + "type": "string" + } + } + }, + "BlobHierarchyListSegment": { + "xml": { + "name": "Blobs" + }, + "type": "object", + "required": [ + "BlobItems" + ], + "properties": { + "BlobPrefixes": { + "type": "array", + "items": { + "$ref": "#/definitions/BlobPrefix" + } + }, + "BlobItems": { + "type": "array", + "items": { + "$ref": "#/definitions/BlobItemInternal" + } + } + } + }, + "BlobPrefix": { + "type": "object", + "required": [ + "Name" + ], + "properties": { + "Name": { + "type": "string" + } + } + }, + "BlobName": { + "type": "object", + "properties": { + "Encoded": { + "xml": { + "attribute": true, + "name": "Encoded" + }, + "type": "boolean", + "description": "Indicates if the blob name is encoded." + }, + "content": { + "xml": { + "x-ms-text": true + }, + "type": "string", + "description": "The name of the blob." + } + } + }, + "BlobTag": { + "xml": { + "name": "Tag" + }, + "type": "object", + "required": [ + "Key", + "Value" + ], + "properties": { + "Key": { + "type": "string" + }, + "Value": { + "type": "string" + } + } + }, + "BlobTags": { + "type": "object", + "xml": { + "name": "Tags" + }, + "description": "Blob tags", + "required": [ + "BlobTagSet" + ], + "properties": { + "BlobTagSet": { + "xml": { + "wrapped": true, + "name": "TagSet" + }, + "type": "array", + "items": { + "$ref": "#/definitions/BlobTag" + } + } + } + }, + "Block": { + "type": "object", + "required": [ + "Name", + "Size" + ], + "description": "Represents a single block in a block blob. It describes the block's ID and size.", + "properties": { + "Name": { + "description": "The base64 encoded block ID.", + "type": "string" + }, + "Size": { + "description": "The block size in bytes.", + "type": "integer", + "format": "int64" + } + } + }, + "BlockList": { + "type": "object", + "properties": { + "CommittedBlocks": { + "xml": { + "wrapped": true + }, + "type": "array", + "items": { + "$ref": "#/definitions/Block" + } + }, + "UncommittedBlocks": { + "xml": { + "wrapped": true + }, + "type": "array", + "items": { + "$ref": "#/definitions/Block" + } + } + } + }, + "BlockLookupList": { + "type": "object", + "properties": { + "Committed": { + "type": "array", + "items": { + "type": "string", + "xml": { + "name": "Committed" + } + } + }, + "Uncommitted": { + "type": "array", + "items": { + "type": "string", + "xml": { + "name": "Uncommitted" + } + } + }, + "Latest": { + "type": "array", + "items": { + "type": "string", + "xml": { + "name": "Latest" + } + } + } + }, + "xml": { + "name": "BlockList" + } + }, + "ContainerItem": { + "xml": { + "name": "Container" + }, + "type": "object", + "required": [ + "Name", + "Properties" + ], + "description": "An Azure Storage container", + "properties": { + "Name": { + "type": "string" + }, + "Deleted": { + "type": "boolean" + }, + "Version": { + "type": "string" + }, + "Properties": { + "$ref": "#/definitions/ContainerProperties" + }, + "Metadata": { + "$ref": "#/definitions/ContainerMetadata" + } + } + }, + "ContainerProperties": { + "type": "object", + "required": [ + "Last-Modified", + "Etag" + ], + "description": "Properties of a container", + "properties": { + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123" + }, + "Etag": { + "type": "string" + }, + "LeaseStatus": { + "$ref": "#/definitions/LeaseStatus" + }, + "LeaseState": { + "$ref": "#/definitions/LeaseState" + }, + "LeaseDuration": { + "$ref": "#/definitions/LeaseDuration" + }, + "PublicAccess": { + "$ref": "#/definitions/PublicAccessType" + }, + "HasImmutabilityPolicy": { + "type": "boolean" + }, + "HasLegalHold": { + "type": "boolean" + }, + "DefaultEncryptionScope": { + "type": "string" + }, + "DenyEncryptionScopeOverride": { + "type": "boolean", + "x-ms-client-name": "PreventEncryptionScopeOverride" + }, + "DeletedTime": { + "type": "string", + "format": "date-time-rfc1123" + }, + "RemainingRetentionDays": { + "type": "integer" + }, + "ImmutableStorageWithVersioningEnabled": { + "x-ms-client-name": "IsImmutableStorageWithVersioningEnabled", + "type": "boolean", + "description": "Indicates if version level worm is enabled on this container." + } + } + }, + "DelimitedTextConfiguration": { + "xml": { + "name": "DelimitedTextConfiguration" + }, + "description": "Groups the settings used for interpreting the blob data if the blob is delimited text formatted.", + "type": "object", + "properties": { + "ColumnSeparator": { + "type": "string", + "description": "The string used to separate columns.", + "xml": { + "name": "ColumnSeparator" + } + }, + "FieldQuote": { + "type": "string", + "description": "The string used to quote a specific field.", + "xml": { + "name": "FieldQuote" + } + }, + "RecordSeparator": { + "type": "string", + "description": "The string used to separate records.", + "xml": { + "name": "RecordSeparator" + } + }, + "EscapeChar": { + "type": "string", + "description": "The string used as an escape character.", + "xml": { + "name": "EscapeChar" + } + }, + "HeadersPresent": { + "type": "boolean", + "description": "Represents whether the data has headers.", + "xml": { + "name": "HasHeaders" + } + } + } + }, + "JsonTextConfiguration": { + "xml": { + "name": "JsonTextConfiguration" + }, + "description": "json text configuration", + "type": "object", + "properties": { + "RecordSeparator": { + "type": "string", + "description": "The string used to separate records.", + "xml": { + "name": "RecordSeparator" + } + } + } + }, + "ArrowConfiguration": { + "xml": { + "name": "ArrowConfiguration" + }, + "description": "Groups the settings used for formatting the response if the response should be Arrow formatted.", + "type": "object", + "required": [ + "Schema" + ], + "properties": { + "Schema": { + "type": "array", + "items": { + "$ref": "#/definitions/ArrowField" + }, + "xml": { + "wrapped": true, + "name": "Schema" + } + } + } + }, + "ParquetConfiguration": { + "xml": { + "name": "ParquetTextConfiguration" + }, + "description": "parquet configuration", + "type": "object" + }, + "ArrowField": { + "xml": { + "name": "Field" + }, + "description": "Groups settings regarding specific field of an arrow schema", + "type": "object", + "required": [ + "Type" + ], + "properties": { + "Type": { + "type": "string" + }, + "Name": { + "type": "string" + }, + "Precision": { + "type": "integer" + }, + "Scale": { + "type": "integer" + } + } + }, + "ListContainersSegmentResponse": { + "xml": { + "name": "EnumerationResults" + }, + "description": "An enumeration of containers", + "type": "object", + "required": [ + "ServiceEndpoint", + "ContainerItems" + ], + "properties": { + "ServiceEndpoint": { + "type": "string", + "xml": { + "attribute": true + } + }, + "Prefix": { + "type": "string" + }, + "Marker": { + "type": "string" + }, + "MaxResults": { + "type": "integer" + }, + "ContainerItems": { + "xml": { + "wrapped": true, + "name": "Containers" + }, + "type": "array", + "items": { + "$ref": "#/definitions/ContainerItem" + } + }, + "NextMarker": { + "type": "string" + } + } + }, + "CorsRule": { + "description": "CORS is an HTTP feature that enables a web application running under one domain to access resources in another domain. Web browsers implement a security restriction known as same-origin policy that prevents a web page from calling APIs in a different domain; CORS provides a secure way to allow one domain (the origin domain) to call APIs in another domain", + "type": "object", + "required": [ + "AllowedOrigins", + "AllowedMethods", + "MaxAgeInSeconds" + ], + "properties": { + "AllowedOrigins": { + "description": "The origin domains that are permitted to make a request against the storage service via CORS. The origin domain is the domain from which the request originates. Note that the origin must be an exact case-sensitive match with the origin that the user age sends to the service. You can also use the wildcard character '*' to allow all origin domains to make requests via CORS.", + "type": "string" + }, + "AllowedMethods": { + "description": "The methods (HTTP request verbs) that the origin domain may use for a CORS request. (comma separated)", + "type": "string" + }, + "AllowedHeaders": { + "description": "the request headers that the origin domain may specify on the CORS request.", + "type": "string" + }, + "ExposedHeaders": { + "description": "The response headers that may be sent in the response to the CORS request and exposed by the browser to the request issuer", + "type": "string" + }, + "MaxAgeInSeconds": { + "description": "The maximum amount time that a browser should cache the preflight OPTIONS request.", + "type": "integer", + "minimum": 0 + } + } + }, + "ErrorCode": { + "description": "Error codes returned by the service", + "type": "string", + "enum": [ + "AccountAlreadyExists", + "AccountBeingCreated", + "AccountIsDisabled", + "AuthenticationFailed", + "AuthorizationFailure", + "ConditionHeadersNotSupported", + "ConditionNotMet", + "EmptyMetadataKey", + "InsufficientAccountPermissions", + "InternalError", + "InvalidAuthenticationInfo", + "InvalidHeaderValue", + "InvalidHttpVerb", + "InvalidInput", + "InvalidMd5", + "InvalidMetadata", + "InvalidQueryParameterValue", + "InvalidRange", + "InvalidResourceName", + "InvalidUri", + "InvalidXmlDocument", + "InvalidXmlNodeValue", + "Md5Mismatch", + "MetadataTooLarge", + "MissingContentLengthHeader", + "MissingRequiredQueryParameter", + "MissingRequiredHeader", + "MissingRequiredXmlNode", + "MultipleConditionHeadersNotSupported", + "OperationTimedOut", + "OutOfRangeInput", + "OutOfRangeQueryParameterValue", + "RequestBodyTooLarge", + "ResourceTypeMismatch", + "RequestUrlFailedToParse", + "ResourceAlreadyExists", + "ResourceNotFound", + "ServerBusy", + "UnsupportedHeader", + "UnsupportedXmlNode", + "UnsupportedQueryParameter", + "UnsupportedHttpVerb", + "AppendPositionConditionNotMet", + "BlobAlreadyExists", + "BlobImmutableDueToPolicy", + "BlobNotFound", + "BlobOverwritten", + "BlobTierInadequateForContentLength", + "BlobUsesCustomerSpecifiedEncryption", + "BlockCountExceedsLimit", + "BlockListTooLong", + "CannotChangeToLowerTier", + "CannotVerifyCopySource", + "ContainerAlreadyExists", + "ContainerBeingDeleted", + "ContainerDisabled", + "ContainerNotFound", + "ContentLengthLargerThanTierLimit", + "CopyAcrossAccountsNotSupported", + "CopyIdMismatch", + "FeatureVersionMismatch", + "IncrementalCopyBlobMismatch", + "IncrementalCopyOfEarlierVersionSnapshotNotAllowed", + "IncrementalCopySourceMustBeSnapshot", + "InfiniteLeaseDurationRequired", + "InvalidBlobOrBlock", + "InvalidBlobTier", + "InvalidBlobType", + "InvalidBlockId", + "InvalidBlockList", + "InvalidOperation", + "InvalidPageRange", + "InvalidSourceBlobType", + "InvalidSourceBlobUrl", + "InvalidVersionForPageBlobOperation", + "LeaseAlreadyPresent", + "LeaseAlreadyBroken", + "LeaseIdMismatchWithBlobOperation", + "LeaseIdMismatchWithContainerOperation", + "LeaseIdMismatchWithLeaseOperation", + "LeaseIdMissing", + "LeaseIsBreakingAndCannotBeAcquired", + "LeaseIsBreakingAndCannotBeChanged", + "LeaseIsBrokenAndCannotBeRenewed", + "LeaseLost", + "LeaseNotPresentWithBlobOperation", + "LeaseNotPresentWithContainerOperation", + "LeaseNotPresentWithLeaseOperation", + "MaxBlobSizeConditionNotMet", + "NoAuthenticationInformation", + "NoPendingCopyOperation", + "OperationNotAllowedOnIncrementalCopyBlob", + "PendingCopyOperation", + "PreviousSnapshotCannotBeNewer", + "PreviousSnapshotNotFound", + "PreviousSnapshotOperationNotSupported", + "SequenceNumberConditionNotMet", + "SequenceNumberIncrementTooLarge", + "SnapshotCountExceeded", + "SnapshotOperationRateExceeded", + "SnapshotsPresent", + "SourceConditionNotMet", + "SystemInUse", + "TargetConditionNotMet", + "UnauthorizedBlobOverwrite", + "BlobBeingRehydrated", + "BlobArchived", + "BlobNotArchived", + "AuthorizationSourceIPMismatch", + "AuthorizationProtocolMismatch", + "AuthorizationPermissionMismatch", + "AuthorizationServiceMismatch", + "AuthorizationResourceTypeMismatch" + ], + "x-ms-enum": { + "name": "StorageErrorCode", + "modelAsString": true + } + }, + "FilterBlobItem": { + "xml": { + "name": "Blob" + }, + "description": "Blob info from a Filter Blobs API call", + "type": "object", + "required": [ + "Name", + "ContainerName" + ], + "properties": { + "Name": { + "type": "string" + }, + "ContainerName": { + "type": "string" + }, + "Tags": { + "$ref": "#/definitions/BlobTags" + }, + "VersionId": { + "type": "string" + }, + "IsCurrentVersion": { + "type": "boolean" + } + } + }, + "FilterBlobSegment": { + "description": "The result of a Filter Blobs API call", + "xml": { + "name": "EnumerationResults" + }, + "type": "object", + "required": [ + "ServiceEndpoint", + "Where", + "Blobs" + ], + "properties": { + "ServiceEndpoint": { + "type": "string", + "xml": { + "attribute": true + } + }, + "Where": { + "type": "string" + }, + "Blobs": { + "xml": { + "name": "Blobs", + "wrapped": true + }, + "type": "array", + "items": { + "$ref": "#/definitions/FilterBlobItem" + } + }, + "NextMarker": { + "type": "string" + } + } + }, + "GeoReplication": { + "description": "Geo-Replication information for the Secondary Storage Service", + "type": "object", + "required": [ + "Status", + "LastSyncTime" + ], + "properties": { + "Status": { + "description": "The status of the secondary location", + "type": "string", + "enum": [ + "live", + "bootstrap", + "unavailable" + ], + "x-ms-enum": { + "name": "GeoReplicationStatusType", + "modelAsString": true + } + }, + "LastSyncTime": { + "description": "A GMT date/time value, to the second. All primary writes preceding this value are guaranteed to be available for read operations at the secondary. Primary writes after this point in time may or may not be available for reads.", + "type": "string", + "format": "date-time-rfc1123" + } + } + }, + "Logging": { + "description": "Azure Analytics Logging settings.", + "type": "object", + "required": [ + "Version", + "Delete", + "Read", + "Write", + "RetentionPolicy" + ], + "properties": { + "Version": { + "description": "The version of Storage Analytics to configure.", + "type": "string" + }, + "Delete": { + "description": "Indicates whether all delete requests should be logged.", + "type": "boolean" + }, + "Read": { + "description": "Indicates whether all read requests should be logged.", + "type": "boolean" + }, + "Write": { + "description": "Indicates whether all write requests should be logged.", + "type": "boolean" + }, + "RetentionPolicy": { + "$ref": "#/definitions/RetentionPolicy" + } + } + }, + "ContainerMetadata": { + "type": "object", + "xml": { + "name": "Metadata" + }, + "additionalProperties": { + "type": "string" + } + }, + "BlobMetadata": { + "type": "object", + "xml": { + "name": "Metadata" + }, + "properties": { + "Encrypted": { + "type": "string", + "xml": { + "attribute": true + } + } + }, + "additionalProperties": { + "type": "string" + } + }, + "ObjectReplicationMetadata": { + "type": "object", + "xml": { + "name": "OrMetadata" + }, + "additionalProperties": { + "type": "string" + } + }, + "Metrics": { + "description": "a summary of request statistics grouped by API in hour or minute aggregates for blobs", + "required": [ + "Enabled" + ], + "properties": { + "Version": { + "description": "The version of Storage Analytics to configure.", + "type": "string" + }, + "Enabled": { + "description": "Indicates whether metrics are enabled for the Blob service.", + "type": "boolean" + }, + "IncludeAPIs": { + "description": "Indicates whether metrics should generate summary statistics for called API operations.", + "type": "boolean" + }, + "RetentionPolicy": { + "$ref": "#/definitions/RetentionPolicy" + } + } + }, + "PageList": { + "description": "the list of pages", + "type": "object", + "properties": { + "PageRange": { + "type": "array", + "items": { + "$ref": "#/definitions/PageRange" + } + }, + "ClearRange": { + "type": "array", + "items": { + "$ref": "#/definitions/ClearRange" + } + }, + "NextMarker": { + "type": "string" + } + } + }, + "PageRange": { + "type": "object", + "required": [ + "Start", + "End" + ], + "properties": { + "Start": { + "type": "integer", + "format": "int64", + "xml": { + "name": "Start" + } + }, + "End": { + "type": "integer", + "format": "int64", + "xml": { + "name": "End" + } + } + }, + "xml": { + "name": "PageRange" + } + }, + "ClearRange": { + "type": "object", + "required": [ + "Start", + "End" + ], + "properties": { + "Start": { + "type": "integer", + "format": "int64", + "xml": { + "name": "Start" + } + }, + "End": { + "type": "integer", + "format": "int64", + "xml": { + "name": "End" + } + } + }, + "xml": { + "name": "ClearRange" + } + }, + "QueryRequest": { + "description": "Groups the set of query request settings.", + "type": "object", + "required": [ + "QueryType", + "Expression" + ], + "properties": { + "QueryType": { + "type": "string", + "description": "Required. The type of the provided query expression.", + "xml": { + "name": "QueryType" + }, + "enum": [ + "SQL" + ] + }, + "Expression": { + "type": "string", + "description": "The query expression in SQL. The maximum size of the query expression is 256KiB.", + "xml": { + "name": "Expression" + } + }, + "InputSerialization": { + "$ref": "#/definitions/QuerySerialization", + "xml": { + "name": "InputSerialization" + } + }, + "OutputSerialization": { + "$ref": "#/definitions/QuerySerialization", + "xml": { + "name": "OutputSerialization" + } + } + }, + "xml": { + "name": "QueryRequest" + } + }, + "QueryFormat": { + "type": "object", + "required": [ + "Type" + ], + "properties": { + "Type": { + "$ref": "#/definitions/QueryType" + }, + "DelimitedTextConfiguration": { + "$ref": "#/definitions/DelimitedTextConfiguration" + }, + "JsonTextConfiguration": { + "$ref": "#/definitions/JsonTextConfiguration" + }, + "ArrowConfiguration": { + "$ref": "#/definitions/ArrowConfiguration" + }, + "ParquetTextConfiguration": { + "$ref": "#/definitions/ParquetConfiguration" + } + } + }, + "QuerySerialization": { + "type": "object", + "required": [ + "Format" + ], + "properties": { + "Format": { + "$ref": "#/definitions/QueryFormat", + "xml": { + "name": "Format" + } + } + } + }, + "QueryType": { + "type": "string", + "description": "The quick query format type.", + "enum": [ + "delimited", + "json", + "arrow", + "parquet" + ], + "x-ms-enum": { + "name": "QueryFormatType", + "modelAsString": false + }, + "xml": { + "name": "Type" + } + }, + "RehydratePriority": { + "description": "If an object is in rehydrate pending state then this header is returned with priority of rehydrate. Valid values are High and Standard.", + "type": "string", + "enum": [ + "High", + "Standard" + ], + "x-ms-enum": { + "name": "RehydratePriority", + "modelAsString": true + }, + "xml": { + "name": "RehydratePriority" + } + }, + "RetentionPolicy": { + "description": "the retention policy which determines how long the associated data should persist", + "type": "object", + "required": [ + "Enabled" + ], + "properties": { + "Enabled": { + "description": "Indicates whether a retention policy is enabled for the storage service", + "type": "boolean" + }, + "Days": { + "description": "Indicates the number of days that metrics or logging or soft-deleted data should be retained. All data older than this value will be deleted", + "type": "integer", + "minimum": 1 + }, + "AllowPermanentDelete": { + "description": "Indicates whether permanent delete is allowed on this storage account.", + "type": "boolean" + } + } + }, + "SignedIdentifier": { + "xml": { + "name": "SignedIdentifier" + }, + "description": "signed identifier", + "type": "object", + "required": [ + "Id", + "AccessPolicy" + ], + "properties": { + "Id": { + "type": "string", + "description": "a unique id" + }, + "AccessPolicy": { + "$ref": "#/definitions/AccessPolicy" + } + } + }, + "SignedIdentifiers": { + "description": "a collection of signed identifiers", + "type": "array", + "items": { + "$ref": "#/definitions/SignedIdentifier" + }, + "xml": { + "wrapped": true, + "name": "SignedIdentifiers" + } + }, + "StaticWebsite": { + "description": "The properties that enable an account to host a static website", + "type": "object", + "required": [ + "Enabled" + ], + "properties": { + "Enabled": { + "description": "Indicates whether this account is hosting a static website", + "type": "boolean" + }, + "IndexDocument": { + "description": "The default name of the index page under each directory", + "type": "string" + }, + "ErrorDocument404Path": { + "description": "The absolute path of the custom 404 page", + "type": "string" + }, + "DefaultIndexDocumentPath": { + "description": "Absolute path of the default index page", + "type": "string" + } + } + }, + "StorageServiceProperties": { + "description": "Storage Service Properties.", + "type": "object", + "properties": { + "Logging": { + "$ref": "#/definitions/Logging" + }, + "HourMetrics": { + "$ref": "#/definitions/Metrics" + }, + "MinuteMetrics": { + "$ref": "#/definitions/Metrics" + }, + "Cors": { + "description": "The set of CORS rules.", + "type": "array", + "items": { + "$ref": "#/definitions/CorsRule" + }, + "xml": { + "wrapped": true + } + }, + "DefaultServiceVersion": { + "description": "The default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions", + "type": "string" + }, + "DeleteRetentionPolicy": { + "$ref": "#/definitions/RetentionPolicy" + }, + "StaticWebsite": { + "$ref": "#/definitions/StaticWebsite" + } + } + }, + "StorageServiceStats": { + "description": "Stats for the storage service.", + "type": "object", + "properties": { + "GeoReplication": { + "$ref": "#/definitions/GeoReplication" + } + } + } + }, + "parameters": { + "Url": { + "name": "url", + "description": "The URL of the service account, container, or blob that is the target of the desired operation.", + "x-ms-parameter-location": "client", + "required": true, + "type": "string", + "in": "path", + "x-ms-skip-url-encoding": true + }, + "ApiVersionParameter": { + "name": "x-ms-version", + "x-ms-parameter-location": "client", + "x-ms-client-name": "version", + "in": "header", + "required": false, + "type": "string", + "description": "Specifies the version of the operation to use for this request." + }, + "BlobCacheControl": { + "name": "x-ms-blob-cache-control", + "x-ms-client-name": "blobCacheControl", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "blob-HTTP-headers" + }, + "description": "Optional. Sets the blob's cache control. If specified, this property is stored with the blob and returned with a read request." + }, + "BlobConditionAppendPos": { + "name": "x-ms-blob-condition-appendpos", + "x-ms-client-name": "appendPosition", + "in": "header", + "required": false, + "type": "integer", + "format": "int64", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "append-position-access-conditions" + }, + "description": "Optional conditional header, used only for the Append Block operation. A number indicating the byte offset to compare. Append Block will succeed only if the append position is equal to this number. If it is not, the request will fail with the AppendPositionConditionNotMet error (HTTP status code 412 - Precondition Failed)." + }, + "BlobConditionMaxSize": { + "name": "x-ms-blob-condition-maxsize", + "x-ms-client-name": "maxSize", + "in": "header", + "required": false, + "type": "integer", + "format": "int64", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "append-position-access-conditions" + }, + "description": "Optional conditional header. The max length in bytes permitted for the append blob. If the Append Block operation would cause the blob to exceed that limit or if the blob size is already greater than the value specified in this header, the request will fail with MaxBlobSizeConditionNotMet error (HTTP status code 412 - Precondition Failed)." + }, + "BlobPublicAccess": { + "name": "x-ms-blob-public-access", + "x-ms-client-name": "access", + "in": "header", + "required": false, + "x-ms-parameter-location": "method", + "description": "Specifies whether data in the container may be accessed publicly and the level of access", + "type": "string", + "enum": [ + "container", + "blob" + ], + "x-ms-enum": { + "name": "PublicAccessType", + "modelAsString": true + } + }, + "BlobTagsBody": { + "name": "Tags", + "in": "body", + "schema": { + "$ref": "#/definitions/BlobTags" + }, + "x-ms-parameter-location": "method", + "description": "Blob tags" + }, + "BlobTagsHeader": { + "name": "x-ms-tags", + "x-ms-client-name": "BlobTagsString", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "description": "Optional. Used to set blob tags in various blob operations." + }, + "AccessTierRequired": { + "name": "x-ms-access-tier", + "x-ms-client-name": "tier", + "in": "header", + "required": true, + "type": "string", + "enum": [ + "P4", + "P6", + "P10", + "P15", + "P20", + "P30", + "P40", + "P50", + "P60", + "P70", + "P80", + "Hot", + "Cool", + "Archive", + "Premium" + ], + "x-ms-enum": { + "name": "AccessTier", + "modelAsString": true + }, + "x-ms-parameter-location": "method", + "description": "Indicates the tier to be set on the blob." + }, + "AccessTierOptional": { + "name": "x-ms-access-tier", + "x-ms-client-name": "tier", + "in": "header", + "required": false, + "type": "string", + "enum": [ + "P4", + "P6", + "P10", + "P15", + "P20", + "P30", + "P40", + "P50", + "P60", + "P70", + "P80", + "Hot", + "Cool", + "Archive", + "Premium" + ], + "x-ms-enum": { + "name": "AccessTier", + "modelAsString": true + }, + "x-ms-parameter-location": "method", + "description": "Optional. Indicates the tier to be set on the blob." + }, + "PremiumPageBlobAccessTierOptional": { + "name": "x-ms-access-tier", + "x-ms-client-name": "tier", + "in": "header", + "required": false, + "type": "string", + "enum": [ + "P4", + "P6", + "P10", + "P15", + "P20", + "P30", + "P40", + "P50", + "P60", + "P70", + "P80" + ], + "x-ms-enum": { + "name": "PremiumPageBlobAccessTier", + "modelAsString": true + }, + "x-ms-parameter-location": "method", + "description": "Optional. Indicates the tier to be set on the page blob." + }, + "RehydratePriority": { + "name": "x-ms-rehydrate-priority", + "x-ms-client-name": "rehydratePriority", + "in": "header", + "required": false, + "type": "string", + "enum": [ + "High", + "Standard" + ], + "x-ms-enum": { + "name": "RehydratePriority", + "modelAsString": true + }, + "x-ms-parameter-location": "method", + "description": "Optional: Indicates the priority with which to rehydrate an archived blob." + }, + "BlobContentDisposition": { + "name": "x-ms-blob-content-disposition", + "x-ms-client-name": "blobContentDisposition", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "blob-HTTP-headers" + }, + "description": "Optional. Sets the blob's Content-Disposition header." + }, + "BlobContentEncoding": { + "name": "x-ms-blob-content-encoding", + "x-ms-client-name": "blobContentEncoding", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "blob-HTTP-headers" + }, + "description": "Optional. Sets the blob's content encoding. If specified, this property is stored with the blob and returned with a read request." + }, + "BlobContentLanguage": { + "name": "x-ms-blob-content-language", + "x-ms-client-name": "blobContentLanguage", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "blob-HTTP-headers" + }, + "description": "Optional. Set the blob's content language. If specified, this property is stored with the blob and returned with a read request." + }, + "BlobContentLengthOptional": { + "name": "x-ms-blob-content-length", + "x-ms-client-name": "blobContentLength", + "in": "header", + "required": false, + "type": "integer", + "format": "int64", + "x-ms-parameter-location": "method", + "description": "This header specifies the maximum size for the page blob, up to 1 TB. The page blob size must be aligned to a 512-byte boundary." + }, + "BlobContentLengthRequired": { + "name": "x-ms-blob-content-length", + "x-ms-client-name": "blobContentLength", + "in": "header", + "required": true, + "type": "integer", + "format": "int64", + "x-ms-parameter-location": "method", + "description": "This header specifies the maximum size for the page blob, up to 1 TB. The page blob size must be aligned to a 512-byte boundary." + }, + "BlobContentMD5": { + "name": "x-ms-blob-content-md5", + "x-ms-client-name": "blobContentMD5", + "in": "header", + "required": false, + "type": "string", + "format": "byte", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "blob-HTTP-headers" + }, + "description": "Optional. An MD5 hash of the blob content. Note that this hash is not validated, as the hashes for the individual blocks were validated when each was uploaded." + }, + "BlobContentType": { + "name": "x-ms-blob-content-type", + "x-ms-client-name": "blobContentType", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "blob-HTTP-headers" + }, + "description": "Optional. Sets the blob's content type. If specified, this property is stored with the blob and returned with a read request." + }, + "BlobDeleteType": { + "name": "deletetype", + "x-ms-client-name": "blobDeleteType", + "in": "query", + "required": false, + "type": "string", + "enum": [ + "Permanent" + ], + "x-ms-enum": { + "name": "BlobDeleteType", + "modelAsString": false + }, + "x-ms-parameter-location": "method", + "description": "Optional. Only possible value is 'permanent', which specifies to permanently delete a blob if blob soft delete is enabled." + }, + "BlobExpiryOptions": { + "name": "x-ms-expiry-option", + "x-ms-client-name": "ExpiryOptions", + "in": "header", + "required": true, + "type": "string", + "enum": [ + "NeverExpire", + "RelativeToCreation", + "RelativeToNow", + "Absolute" + ], + "x-ms-enum": { + "name": "BlobExpiryOptions", + "modelAsString": true + }, + "x-ms-parameter-location": "method", + "description": "Required. Indicates mode of the expiry time" + }, + "BlobExpiryTime": { + "name": "x-ms-expiry-time", + "x-ms-client-name": "ExpiresOn", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "description": "The time to set the blob to expiry" + }, + "BlobSequenceNumber": { + "name": "x-ms-blob-sequence-number", + "x-ms-client-name": "blobSequenceNumber", + "in": "header", + "required": false, + "type": "integer", + "format": "int64", + "default": 0, + "x-ms-parameter-location": "method", + "description": "Set for page blobs only. The sequence number is a user-controlled value that you can use to track requests. The value of the sequence number must be between 0 and 2^63 - 1." + }, + "BlockId": { + "name": "blockid", + "x-ms-client-name": "blockId", + "in": "query", + "type": "string", + "required": true, + "x-ms-parameter-location": "method", + "description": "A valid Base64 string value that identifies the block. Prior to encoding, the string must be less than or equal to 64 bytes in size. For a given blob, the length of the value specified for the blockid parameter must be the same size for each block." + }, + "BlockListType": { + "name": "blocklisttype", + "x-ms-client-name": "listType", + "in": "query", + "required": false, + "default": "committed", + "x-ms-parameter-location": "method", + "description": "Specifies whether to return the list of committed blocks, the list of uncommitted blocks, or both lists together.", + "type": "string", + "enum": [ + "committed", + "uncommitted", + "all" + ], + "x-ms-enum": { + "name": "BlockListType", + "modelAsString": false + } + }, + "Body": { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "format": "file" + }, + "x-ms-parameter-location": "method", + "description": "Initial data" + }, + "ContainerAcl": { + "name": "containerAcl", + "in": "body", + "schema": { + "$ref": "#/definitions/SignedIdentifiers" + }, + "x-ms-parameter-location": "method", + "description": "the acls for the container" + }, + "CopyId": { + "name": "copyid", + "x-ms-client-name": "copyId", + "in": "query", + "required": true, + "type": "string", + "x-ms-parameter-location": "method", + "description": "The copy identifier provided in the x-ms-copy-id header of the original Copy Blob operation." + }, + "ClientRequestId": { + "name": "x-ms-client-request-id", + "x-ms-client-name": "requestId", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "description": "Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled." + }, + "ContentCrc64": { + "name": "x-ms-content-crc64", + "x-ms-client-name": "transactionalContentCrc64", + "in": "header", + "required": false, + "type": "string", + "format": "byte", + "x-ms-parameter-location": "method", + "description": "Specify the transactional crc64 for the body, to be validated by the service." + }, + "ContentLengthBlob": { + "name": "Content-Length", + "in": "header", + "required": true, + "type": "integer", + "format": "int64", + "x-ms-parameter-location": "method", + "description": "The length of the request." + }, + "ContentMD5Blob": { + "name": "Content-MD5", + "x-ms-client-name": "transactionalContentMD5", + "in": "header", + "required": false, + "type": "string", + "format": "byte", + "x-ms-parameter-location": "method", + "description": "Specify the transactional md5 for the body, to be validated by the service." + }, + "CopySource": { + "name": "x-ms-copy-source", + "x-ms-client-name": "copySource", + "in": "header", + "required": true, + "type": "string", + "x-ms-parameter-location": "method", + "description": "Specifies the name of the source page blob snapshot. This value is a URL of up to 2 KB in length that specifies a page blob snapshot. The value should be URL-encoded as it would appear in a request URI. The source blob must either be public or must be authenticated via a shared access signature." + }, + "CopySourceAuthorization": { + "name": "x-ms-copy-source-authorization", + "x-ms-client-name": "copySourceAuthorization", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "description": "Only Bearer type is supported. Credentials should be a valid OAuth access token to copy source." + }, + "CopySourceBlobProperties": { + "name": "x-ms-copy-source-blob-properties", + "x-ms-client-name": "copySourceBlobProperties", + "in": "header", + "required": false, + "type": "boolean", + "x-ms-parameter-location": "method", + "description": "Optional, default is true. Indicates if properties from the source blob should be copied." + }, + "CopySourceTags": { + "name": "x-ms-copy-source-tag-option", + "x-ms-client-name": "copySourceTags", + "in": "header", + "required": false, + "type": "string", + "enum": [ + "REPLACE", + "COPY" + ], + "x-ms-enum": { + "name": "BlobCopySourceTags", + "modelAsString": false + }, + "x-ms-parameter-location": "method", + "description": "Optional, default 'replace'. Indicates if source tags should be copied or replaced with the tags specified by x-ms-tags." + }, + "DeleteSnapshots": { + "name": "x-ms-delete-snapshots", + "x-ms-client-name": "deleteSnapshots", + "description": "Required if the blob has associated snapshots. Specify one of the following two options: include: Delete the base blob and all of its snapshots. only: Delete only the blob's snapshots and not the blob itself", + "x-ms-parameter-location": "method", + "in": "header", + "required": false, + "type": "string", + "enum": [ + "include", + "only" + ], + "x-ms-enum": { + "name": "DeleteSnapshotsOptionType", + "modelAsString": false + } + }, + "EncryptionKey": { + "name": "x-ms-encryption-key", + "x-ms-client-name": "encryptionKey", + "type": "string", + "in": "header", + "required": false, + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "cpk-info" + }, + "description": "Optional. Specifies the encryption key to use to encrypt the data provided in the request. If not specified, encryption is performed with the root account encryption key. For more information, see Encryption at Rest for Azure Storage Services." + }, + "EncryptionKeySha256": { + "name": "x-ms-encryption-key-sha256", + "x-ms-client-name": "encryptionKeySha256", + "type": "string", + "in": "header", + "required": false, + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "cpk-info" + }, + "description": "The SHA-256 hash of the provided encryption key. Must be provided if the x-ms-encryption-key header is provided." + }, + "EncryptionAlgorithm": { + "name": "x-ms-encryption-algorithm", + "x-ms-client-name": "encryptionAlgorithm", + "type": "string", + "in": "header", + "required": false, + "enum": [ + "AES256" + ], + "x-ms-enum": { + "name": "EncryptionAlgorithmType", + "modelAsString": false + }, + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "cpk-info" + }, + "description": "The algorithm used to produce the encryption key hash. Currently, the only accepted value is \"AES256\". Must be provided if the x-ms-encryption-key header is provided." + }, + "EncryptionScope": { + "name": "x-ms-encryption-scope", + "x-ms-client-name": "encryptionScope", + "type": "string", + "in": "header", + "required": false, + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "cpk-scope-info" + }, + "description": "Optional. Version 2019-07-07 and later. Specifies the name of the encryption scope to use to encrypt the data provided in the request. If not specified, encryption is performed with the default account encryption scope. For more information, see Encryption at Rest for Azure Storage Services." + }, + "DefaultEncryptionScope": { + "name": "x-ms-default-encryption-scope", + "x-ms-client-name": "DefaultEncryptionScope", + "type": "string", + "in": "header", + "required": false, + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "container-cpk-scope-info" + }, + "description": "Optional. Version 2019-07-07 and later. Specifies the default encryption scope to set on the container and use for all future writes." + }, + "DeletedContainerName": { + "name": "x-ms-deleted-container-name", + "x-ms-client-name": "DeletedContainerName", + "type": "string", + "in": "header", + "required": false, + "x-ms-parameter-location": "method", + "description": "Optional. Version 2019-12-12 and later. Specifies the name of the deleted container to restore." + }, + "DeletedContainerVersion": { + "name": "x-ms-deleted-container-version", + "x-ms-client-name": "DeletedContainerVersion", + "type": "string", + "in": "header", + "required": false, + "x-ms-parameter-location": "method", + "description": "Optional. Version 2019-12-12 and later. Specifies the version of the deleted container to restore." + }, + "DenyEncryptionScopeOverride": { + "name": "x-ms-deny-encryption-scope-override", + "x-ms-client-name": "PreventEncryptionScopeOverride", + "type": "boolean", + "in": "header", + "required": false, + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "container-cpk-scope-info" + }, + "description": "Optional. Version 2019-07-07 and newer. If true, prevents any request from specifying a different encryption scope than the scope set on the container." + }, + "FilterBlobsInclude": { + "name": "include", + "in": "query", + "required": false, + "type": "array", + "collectionFormat": "csv", + "items": { + "type": "string", + "enum": [ + "none", + "versions" + ], + "x-ms-enum": { + "name": "FilterBlobsIncludeItem", + "modelAsString": false + } + }, + "x-ms-parameter-location": "method", + "description": "Include this parameter to specify one or more datasets to include in the response." + }, + "FilterBlobsWhere": { + "name": "where", + "in": "query", + "required": false, + "type": "string", + "description": "Filters the results to return only to return only blobs whose tags match the specified expression.", + "x-ms-parameter-location": "method" + }, + "IfMatch": { + "name": "If-Match", + "x-ms-client-name": "ifMatch", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "modified-access-conditions" + }, + "description": "Specify an ETag value to operate only on blobs with a matching value." + }, + "IfModifiedSince": { + "name": "If-Modified-Since", + "x-ms-client-name": "ifModifiedSince", + "in": "header", + "required": false, + "type": "string", + "format": "date-time-rfc1123", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "modified-access-conditions" + }, + "description": "Specify this header value to operate only on a blob if it has been modified since the specified date/time." + }, + "IfNoneMatch": { + "name": "If-None-Match", + "x-ms-client-name": "ifNoneMatch", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "modified-access-conditions" + }, + "description": "Specify an ETag value to operate only on blobs without a matching value." + }, + "IfUnmodifiedSince": { + "name": "If-Unmodified-Since", + "x-ms-client-name": "ifUnmodifiedSince", + "in": "header", + "required": false, + "type": "string", + "format": "date-time-rfc1123", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "modified-access-conditions" + }, + "description": "Specify this header value to operate only on a blob if it has not been modified since the specified date/time." + }, + "IfSequenceNumberEqualTo": { + "name": "x-ms-if-sequence-number-eq", + "x-ms-client-name": "ifSequenceNumberEqualTo", + "in": "header", + "required": false, + "type": "integer", + "format": "int64", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "sequence-number-access-conditions" + }, + "description": "Specify this header value to operate only on a blob if it has the specified sequence number." + }, + "IfSequenceNumberLessThan": { + "name": "x-ms-if-sequence-number-lt", + "x-ms-client-name": "ifSequenceNumberLessThan", + "in": "header", + "required": false, + "type": "integer", + "format": "int64", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "sequence-number-access-conditions" + }, + "description": "Specify this header value to operate only on a blob if it has a sequence number less than the specified." + }, + "IfSequenceNumberLessThanOrEqualTo": { + "name": "x-ms-if-sequence-number-le", + "x-ms-client-name": "ifSequenceNumberLessThanOrEqualTo", + "in": "header", + "required": false, + "type": "integer", + "format": "int64", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "sequence-number-access-conditions" + }, + "description": "Specify this header value to operate only on a blob if it has a sequence number less than or equal to the specified." + }, + "IfTags": { + "name": "x-ms-if-tags", + "x-ms-client-name": "ifTags", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "modified-access-conditions" + }, + "description": "Specify a SQL where clause on blob tags to operate only on blobs with a matching value." + }, + "ImmutabilityPolicyExpiry": { + "name": "x-ms-immutability-policy-until-date", + "x-ms-client-name": "immutabilityPolicyExpiry", + "in": "header", + "required": false, + "type": "string", + "format": "date-time-rfc1123", + "x-ms-parameter-location": "method", + "description": "Specifies the date time when the blobs immutability policy is set to expire." + }, + "ImmutabilityPolicyMode": { + "name": "x-ms-immutability-policy-mode", + "x-ms-client-name": "immutabilityPolicyMode", + "in": "header", + "required": false, + "type": "string", + "enum": [ + "Mutable", + "Unlocked", + "Locked" + ], + "x-ms-enum": { + "name": "BlobImmutabilityPolicyMode", + "modelAsString": false + }, + "x-ms-parameter-location": "method", + "description": "Specifies the immutability policy mode to set on the blob." + }, + "KeyInfo": { + "description": "Key information", + "name": "KeyInfo", + "in": "body", + "x-ms-parameter-location": "method", + "required": true, + "schema": { + "$ref": "#/definitions/KeyInfo" + } + }, + "ListContainersInclude": { + "name": "include", + "in": "query", + "required": false, + "type": "array", + "collectionFormat": "csv", + "items": { + "type": "string", + "enum": [ + "", + "metadata", + "deleted", + "system" + ], + "x-ms-enum": { + "name": "ListContainersIncludeType", + "modelAsString": false + } + }, + "x-ms-parameter-location": "method", + "description": "Include this parameter to specify that the container's metadata be returned as part of the response body." + }, + "LeaseBreakPeriod": { + "name": "x-ms-lease-break-period", + "x-ms-client-name": "breakPeriod", + "in": "header", + "required": false, + "type": "integer", + "x-ms-parameter-location": "method", + "description": "For a break operation, proposed duration the lease should continue before it is broken, in seconds, between 0 and 60. This break period is only used if it is shorter than the time remaining on the lease. If longer, the time remaining on the lease is used. A new lease will not be available before the break period has expired, but the lease may be held for longer than the break period. If this header does not appear with a break operation, a fixed-duration lease breaks after the remaining lease period elapses, and an infinite lease breaks immediately." + }, + "LeaseDurationBlob": { + "name": "x-ms-lease-duration", + "x-ms-client-name": "duration", + "in": "header", + "required": false, + "type": "integer", + "x-ms-parameter-location": "method", + "description": "Specifies the duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A non-infinite lease can be between 15 and 60 seconds. A lease duration cannot be changed using renew or change." + }, + "LeaseIdOptional": { + "name": "x-ms-lease-id", + "x-ms-client-name": "leaseId", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "lease-access-conditions" + }, + "description": "If specified, the operation only succeeds if the resource's lease is active and matches this ID." + }, + "LeaseIdRequired": { + "name": "x-ms-lease-id", + "x-ms-client-name": "leaseId", + "in": "header", + "required": true, + "type": "string", + "x-ms-parameter-location": "method", + "description": "Specifies the current lease ID on the resource." + }, + "LegalHoldOptional": { + "name": "x-ms-legal-hold", + "x-ms-client-name": "legalHold", + "in": "header", + "required": false, + "type": "boolean", + "x-ms-parameter-location": "method", + "description": "Specified if a legal hold should be set on the blob." + }, + "LegalHoldRequired": { + "name": "x-ms-legal-hold", + "x-ms-client-name": "legalHold", + "in": "header", + "required": true, + "type": "boolean", + "x-ms-parameter-location": "method", + "description": "Specified if a legal hold should be set on the blob." + }, + "Marker": { + "name": "marker", + "in": "query", + "required": false, + "type": "string", + "description": "A string value that identifies the portion of the list of containers to be returned with the next listing operation. The operation returns the NextMarker value within the response body if the listing operation did not return all containers remaining to be listed with the current page. The NextMarker value can be used as the value for the marker parameter in a subsequent call to request the next page of list items. The marker value is opaque to the client.", + "x-ms-parameter-location": "method" + }, + "MaxResultsBlob": { + "name": "maxresults", + "in": "query", + "required": false, + "type": "integer", + "minimum": 1, + "x-ms-parameter-location": "method", + "description": "Specifies the maximum number of containers to return. If the request does not specify maxresults, or specifies a value greater than 5000, the server will return up to 5000 items. Note that if the listing operation crosses a partition boundary, then the service will return a continuation token for retrieving the remainder of the results. For this reason, it is possible that the service will return fewer results than specified by maxresults, or than the default of 5000." + }, + "Metadata": { + "name": "x-ms-meta", + "x-ms-client-name": "metadata", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "description": "Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or file to the destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more information.", + "x-ms-header-collection-prefix": "x-ms-meta-" + }, + "MultipartContentType": { + "name": "Content-Type", + "x-ms-client-name": "multipartContentType", + "in": "header", + "required": true, + "type": "string", + "x-ms-parameter-location": "method", + "description": "Required. The value of this header must be multipart/mixed with a batch boundary. Example header value: multipart/mixed; boundary=batch_" + }, + "ObjectReplicationPolicyId": { + "name": "x-ms-or-policy-id", + "x-ms-client-name": "objectReplicationPolicyId", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "description": "Optional. Only valid when Object Replication is enabled for the storage container and on the destination blob of the replication." + }, + "ObjectReplicationRules": { + "name": "x-ms-or", + "x-ms-client-name": "ObjectReplicationRules", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "description": "Optional. Only valid when Object Replication is enabled for the storage container and on the source blob of the replication. When retrieving this header, it will return the header with the policy id and rule id (e.g. x-ms-or-policyid_ruleid), and the value will be the status of the replication (e.g. complete, failed).", + "x-ms-header-collection-prefix": "x-ms-or-" + }, + "Prefix": { + "name": "prefix", + "in": "query", + "required": false, + "type": "string", + "description": "Filters results to filesystems within the specified prefix.", + "x-ms-parameter-location": "method" + }, + "PrevSnapshot": { + "name": "prevsnapshot", + "in": "query", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "description": "Optional in version 2015-07-08 and newer. The prevsnapshot parameter is a DateTime value that specifies that the response will contain only pages that were changed between target blob and previous snapshot. Changed pages include both updated and cleared pages. The target blob may be a snapshot, as long as the snapshot specified by prevsnapshot is the older of the two. Note that incremental snapshots are currently supported only for blobs created on or after January 1, 2016." + }, + "PrevSnapshotUrl": { + "name": "x-ms-previous-snapshot-url", + "x-ms-client-name": "prevSnapshotUrl", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "description": "Optional. This header is only supported in service versions 2019-04-19 and after and specifies the URL of a previous snapshot of the target blob. The response will only contain pages that were changed between the target blob and its previous snapshot." + }, + "ProposedLeaseIdOptional": { + "name": "x-ms-proposed-lease-id", + "x-ms-client-name": "proposedLeaseId", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "description": "Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid Constructor (String) for a list of valid GUID string formats." + }, + "ProposedLeaseIdRequired": { + "name": "x-ms-proposed-lease-id", + "x-ms-client-name": "proposedLeaseId", + "in": "header", + "required": true, + "type": "string", + "x-ms-parameter-location": "method", + "description": "Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid Constructor (String) for a list of valid GUID string formats." + }, + "QueryRequest": { + "name": "queryRequest", + "in": "body", + "x-ms-parameter-location": "client", + "schema": { + "$ref": "#/definitions/QueryRequest" + }, + "description": "the query request" + }, + "Range": { + "name": "x-ms-range", + "x-ms-client-name": "range", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "description": "The HTTP Range request header specifies one or more byte ranges of the resource to be retrieved." + }, + "RangeRequiredPutPageFromUrl": { + "name": "x-ms-range", + "x-ms-client-name": "range", + "in": "header", + "required": true, + "type": "string", + "x-ms-parameter-location": "method", + "description": "The range of bytes to which the source range would be written. The range should be 512 aligned and range-end is required." + }, + "SequenceNumberAction": { + "name": "x-ms-sequence-number-action", + "x-ms-client-name": "sequenceNumberAction", + "in": "header", + "required": true, + "x-ms-parameter-location": "method", + "description": "Required if the x-ms-blob-sequence-number header is set for the request. This property applies to page blobs only. This property indicates how the service should modify the blob's sequence number", + "type": "string", + "enum": [ + "max", + "update", + "increment" + ], + "x-ms-enum": { + "name": "SequenceNumberActionType", + "modelAsString": false + } + }, + "Snapshot": { + "name": "snapshot", + "in": "query", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "description": "The snapshot parameter is an opaque DateTime value that, when present, specifies the blob snapshot to retrieve. For more information on working with blob snapshots, see Creating a Snapshot of a Blob." + }, + "VersionId": { + "name": "versionid", + "x-ms-client-name": "versionId", + "in": "query", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "description": "The version id parameter is an opaque DateTime value that, when present, specifies the version of the blob to operate on. It's for service version 2019-10-10 and newer." + }, + "SealBlob": { + "name": "x-ms-seal-blob", + "x-ms-client-name": "SealBlob", + "in": "header", + "required": false, + "type": "boolean", + "x-ms-parameter-location": "method", + "description": "Overrides the sealed state of the destination blob. Service version 2019-12-12 and newer." + }, + "SourceContainerName": { + "name": "x-ms-source-container-name", + "x-ms-client-name": "SourceContainerName", + "type": "string", + "in": "header", + "required": true, + "x-ms-parameter-location": "method", + "description": "Required. Specifies the name of the container to rename." + }, + "SourceContentMD5": { + "name": "x-ms-source-content-md5", + "x-ms-client-name": "sourceContentMD5", + "in": "header", + "required": false, + "type": "string", + "format": "byte", + "x-ms-parameter-location": "method", + "description": "Specify the md5 calculated for the range of bytes that must be read from the copy source." + }, + "SourceContentCRC64": { + "name": "x-ms-source-content-crc64", + "x-ms-client-name": "sourceContentcrc64", + "in": "header", + "required": false, + "type": "string", + "format": "byte", + "x-ms-parameter-location": "method", + "description": "Specify the crc64 calculated for the range of bytes that must be read from the copy source." + }, + "SourceRange": { + "name": "x-ms-source-range", + "x-ms-client-name": "sourceRange", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "description": "Bytes of source data in the specified range." + }, + "SourceRangeRequiredPutPageFromUrl": { + "name": "x-ms-source-range", + "x-ms-client-name": "sourceRange", + "in": "header", + "required": true, + "type": "string", + "x-ms-parameter-location": "method", + "description": "Bytes of source data in the specified range. The length of this range should match the ContentLength header and x-ms-range/Range destination range header." + }, + "SourceIfMatch": { + "name": "x-ms-source-if-match", + "x-ms-client-name": "sourceIfMatch", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "source-modified-access-conditions" + }, + "description": "Specify an ETag value to operate only on blobs with a matching value." + }, + "SourceIfModifiedSince": { + "name": "x-ms-source-if-modified-since", + "x-ms-client-name": "sourceIfModifiedSince", + "in": "header", + "required": false, + "type": "string", + "format": "date-time-rfc1123", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "source-modified-access-conditions" + }, + "description": "Specify this header value to operate only on a blob if it has been modified since the specified date/time." + }, + "SourceIfNoneMatch": { + "name": "x-ms-source-if-none-match", + "x-ms-client-name": "sourceIfNoneMatch", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "source-modified-access-conditions" + }, + "description": "Specify an ETag value to operate only on blobs without a matching value." + }, + "SourceIfUnmodifiedSince": { + "name": "x-ms-source-if-unmodified-since", + "x-ms-client-name": "sourceIfUnmodifiedSince", + "in": "header", + "required": false, + "type": "string", + "format": "date-time-rfc1123", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "source-modified-access-conditions" + }, + "description": "Specify this header value to operate only on a blob if it has not been modified since the specified date/time." + }, + "SourceLeaseId": { + "name": "x-ms-source-lease-id", + "x-ms-client-name": "sourceLeaseId", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "description": "A lease ID for the source path. If specified, the source path must have an active lease and the lease ID must match." + }, + "SourceIfTags": { + "name": "x-ms-source-if-tags", + "x-ms-client-name": "sourceIfTags", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "source-modified-access-conditions" + }, + "description": "Specify a SQL where clause on blob tags to operate only on blobs with a matching value." + }, + "SourceUrl": { + "name": "x-ms-copy-source", + "x-ms-client-name": "sourceUrl", + "in": "header", + "required": true, + "type": "string", + "x-ms-parameter-location": "method", + "description": "Specify a URL to the copy source." + }, + "StorageServiceProperties": { + "name": "StorageServiceProperties", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/StorageServiceProperties" + }, + "x-ms-parameter-location": "method", + "description": "The StorageService properties." + }, + "Timeout": { + "name": "timeout", + "in": "query", + "required": false, + "type": "integer", + "minimum": 0, + "x-ms-parameter-location": "method", + "description": "The timeout parameter is expressed in seconds. For more information, see Setting Timeouts for Blob Service Operations." + } + } +} diff --git a/swagger/data-lake-storage.json-2021-04-10.json b/swagger/data-lake-storage.json-2021-04-10.json new file mode 100644 index 000000000..5b256a570 --- /dev/null +++ b/swagger/data-lake-storage.json-2021-04-10.json @@ -0,0 +1,4592 @@ +{ + "swagger": "2.0", + "info": { + "description": "Azure Data Lake Storage provides storage for Hadoop and other big data workloads.", + "title": "Azure Data Lake Storage REST API", + "version": "2021-04-10", + "x-ms-code-generation-settings": { + "internalConstructors": true, + "name": "DataLakeStorageClient", + "header": "MIT", + "strictSpecAdherence": false + } + }, + "x-ms-parameterized-host": { + "hostTemplate": "{url}", + "useSchemePrefix": false, + "positionInOperation": "first", + "parameters": [ + { + "$ref": "#/parameters/Url" + } + ] + }, + "schemes": ["https"], + "consumes": ["application/json"], + "produces": ["application/json"], + "paths": {}, + "x-ms-paths": { + "/": { + "get": { + "operationId": "Service_ListFileSystems", + "summary": "List FileSystems", + "description": "List filesystems and their properties in given account.", + "x-ms-pageable": { + "itemName": "filesystems", + "nextLinkName": null + }, + "tags": ["Account Operations"], + "parameters": [ + { + "name": "resource", + "in": "query", + "description": "The value must be \"account\" for all account operations.", + "required": true, + "type": "string", + "enum": ["account"], + "x-ms-enum": { + "name": "AccountResourceType", + "modelAsString": false + } + }, + { + "$ref": "#/parameters/Prefix" + }, + { + "$ref": "#/parameters/Continuation" + }, + { + "$ref": "#/parameters/MaxResults" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "OK", + "headers": { + "Date": { + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated.", + "type": "string", + "format": "date-time-rfc1123" + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation.", + "pattern": "^[{(]?[0-9a-f]{8}[-]?([0-9a-f]{4}[-]?){3}[0-9a-f]{12}[)}]?$", + "type": "string" + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "description": "The version of the REST protocol used to process the request.", + "type": "string" + }, + "x-ms-continuation": { + "x-ms-client-name": "Continuation", + "description": "If the number of filesystems to be listed exceeds the maxResults limit, a continuation token is returned in this response header. When a continuation token is returned in the response, it must be specified in a subsequent invocation of the list operation to continue listing the filesystems.", + "type": "string" + }, + "Content-Type": { + "description": "The content type of list filesystem response. The default content type is application/json.", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/FileSystemList" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + } + }, + "/{filesystem}": { + "put": { + "operationId": "FileSystem_Create", + "summary": "Create FileSystem", + "description": "Create a FileSystem rooted at the specified location. If the FileSystem already exists, the operation fails. This operation does not support conditional HTTP requests.", + "tags": ["FileSystem Operations"], + "parameters": [ + { + "$ref": "#/parameters/Properties" + } + ], + "responses": { + "201": { + "description": "Created", + "headers": { + "Date": { + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated.", + "type": "string", + "format": "date-time-rfc1123" + }, + "ETag": { + "description": "An HTTP entity tag associated with the FileSystem.", + "type": "string" + }, + "Last-Modified": { + "description": "The data and time the filesystem was last modified. Operations on files and directories do not affect the last modified time.", + "format": "date-time-rfc1123", + "type": "string" + }, + "x-ms-request-id": { + "x-ms-client-name": "ClientRequestId", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation.", + "pattern": "^[{(]?[0-9a-f]{8}[-]?([0-9a-f]{4}[-]?){3}[0-9a-f]{12}[)}]?$", + "type": "string" + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "description": "The version of the REST protocol used to process the request.", + "type": "string" + }, + "x-ms-namespace-enabled": { + "x-ms-client-name": "NamespaceEnabled", + "description": "A bool string indicates whether the namespace feature is enabled. If \"true\", the namespace is enabled for the filesystem.", + "type": "string" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "patch": { + "operationId": "FileSystem_SetProperties", + "summary": "Set FileSystem Properties", + "description": "Set properties for the FileSystem. This operation supports conditional HTTP requests. For more information, see [Specifying Conditional Headers for Blob Service Operations](https://docs.microsoft.com/en-us/rest/api/storageservices/specifying-conditional-headers-for-blob-service-operations).", + "tags": ["FileSystem Operations"], + "parameters": [ + { + "$ref": "#/parameters/Properties" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + } + ], + "responses": { + "200": { + "description": "Ok", + "headers": { + "Date": { + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated.", + "type": "string", + "format": "date-time-rfc1123" + }, + "ETag": { + "description": "An HTTP entity tag associated with the filesystem. Changes to filesystem properties affect the entity tag, but operations on files and directories do not.", + "type": "string" + }, + "Last-Modified": { + "description": "The data and time the filesystem was last modified. Changes to filesystem properties update the last modified time, but operations on files and directories do not.", + "format": "date-time-rfc1123", + "type": "string" + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation.", + "pattern": "^[{(]?[0-9a-f]{8}[-]?([0-9a-f]{4}[-]?){3}[0-9a-f]{12}[)}]?$", + "type": "string" + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "description": "The version of the REST protocol used to process the request.", + "type": "string" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "head": { + "operationId": "FileSystem_GetProperties", + "summary": "Get FileSystem Properties.", + "description": "All system and user-defined filesystem properties are specified in the response headers.", + "tags": ["FileSystem Operations"], + "responses": { + "200": { + "description": "Ok", + "headers": { + "Date": { + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated.", + "type": "string", + "format": "date-time-rfc1123" + }, + "ETag": { + "description": "An HTTP entity tag associated with the filesystem. Changes to filesystem properties affect the entity tag, but operations on files and directories do not.", + "type": "string" + }, + "Last-Modified": { + "description": "The data and time the filesystem was last modified. Changes to filesystem properties update the last modified time, but operations on files and directories do not.", + "format": "date-time-rfc1123", + "type": "string" + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation.", + "pattern": "^[{(]?[0-9a-f]{8}[-]?([0-9a-f]{4}[-]?){3}[0-9a-f]{12}[)}]?$", + "type": "string" + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "description": "The version of the REST protocol used to process the request.", + "type": "string" + }, + "x-ms-properties": { + "x-ms-client-name": "Properties", + "description": "The user-defined properties associated with the filesystem. A comma-separated list of name and value pairs in the format \"n1=v1, n2=v2, ...\", where each value is a base64 encoded string. Note that the string may only contain ASCII characters in the ISO-8859-1 character set.", + "type": "string" + }, + "x-ms-namespace-enabled": { + "x-ms-client-name": "NamespaceEnabled", + "description": "A bool string indicates whether the namespace feature is enabled. If \"true\", the namespace is enabled for the filesystem.", + "type": "string" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "delete": { + "operationId": "FileSystem_Delete", + "summary": "Delete FileSystem", + "description": "Marks the FileSystem for deletion. When a FileSystem is deleted, a FileSystem with the same identifier cannot be created for at least 30 seconds. While the filesystem is being deleted, attempts to create a filesystem with the same identifier will fail with status code 409 (Conflict), with the service returning additional error information indicating that the filesystem is being deleted. All other operations, including operations on any files or directories within the filesystem, will fail with status code 404 (Not Found) while the filesystem is being deleted. This operation supports conditional HTTP requests. For more information, see [Specifying Conditional Headers for Blob Service Operations](https://docs.microsoft.com/en-us/rest/api/storageservices/specifying-conditional-headers-for-blob-service-operations).", + "tags": ["FileSystem Operations"], + "responses": { + "202": { + "description": "Accepted", + "headers": { + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation.", + "pattern": "^[{(]?[0-9a-f]{8}[-]?([0-9a-f]{4}[-]?){3}[0-9a-f]{12}[)}]?$", + "type": "string" + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "description": "The version of the REST protocol used to process the request.", + "type": "string" + }, + "Date": { + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated.", + "type": "string", + "format": "date-time-rfc1123" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + }, + "parameters": [ + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + } + ] + }, + "parameters": [ + { + "$ref": "#/parameters/FileSystem" + }, + { + "$ref": "#/parameters/FileSystemResource" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ] + }, + "/{filesystem}?resource=filesystem": { + "get": { + "operationId": "FileSystem_ListPaths", + "summary": "List Paths", + "description": "List FileSystem paths and their properties.", + "x-ms-pageable": { + "itemName": "paths", + "nextLinkName": null + }, + "tags": ["FileSystem Operations"], + "parameters": [ + { + "$ref": "#/parameters/Continuation" + }, + { + "$ref": "#/parameters/Directory" + }, + { + "$ref": "#/parameters/RecursiveRequired" + }, + { + "$ref": "#/parameters/MaxResults" + }, + { + "$ref": "#/parameters/Upn" + } + ], + "consumes": ["application/json"], + "produces": ["application/xml"], + "responses": { + "200": { + "description": "Ok", + "headers": { + "Date": { + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated.", + "type": "string", + "format": "date-time-rfc1123" + }, + "ETag": { + "description": "An HTTP entity tag associated with the filesystem. Changes to filesystem properties affect the entity tag, but operations on files and directories do not.", + "type": "string" + }, + "Last-Modified": { + "description": "The data and time the filesystem was last modified. Changes to filesystem properties update the last modified time, but operations on files and directories do not.", + "format": "date-time-rfc1123", + "type": "string" + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation.", + "pattern": "^[{(]?[0-9a-f]{8}[-]?([0-9a-f]{4}[-]?){3}[0-9a-f]{12}[)}]?$", + "type": "string" + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "description": "The version of the REST protocol used to process the request.", + "type": "string" + }, + "x-ms-continuation": { + "x-ms-client-name": "Continuation", + "description": "If the number of paths to be listed exceeds the maxResults limit, a continuation token is returned in this response header. When a continuation token is returned in the response, it must be specified in a subsequent invocation of the list operation to continue listing the paths.", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/PathList" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "$ref": "#/parameters/FileSystem" + }, + { + "$ref": "#/parameters/FileSystemResource" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ] + }, + "/{filesystem}?restype=container&comp=list&flat": { + "get": { + "tags": ["containers"], + "operationId": "FileSystem_ListBlobFlatSegment", + "description": "[Update] The List Blobs operation returns a list of the blobs under the specified container", + "parameters": [ + { + "$ref": "#/parameters/Prefix" + }, + { + "$ref": "#/parameters/Marker" + }, + { + "$ref": "#/parameters/MaxResults" + }, + { + "$ref": "#/parameters/MaxResultsBlob" + }, + { + "$ref": "#/parameters/ListBlobsInclude" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "Success.", + "headers": { + "Content-Type": { + "type": "string", + "description": "The media type of the body of the response. For List Blobs this is 'application/xml'" + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + }, + "schema": { + "$ref": "#/definitions/ListBlobsFlatSegmentResponse" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "NextMarker" + } + }, + "parameters": [ + { + "name": "restype", + "description": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": ["container"] + }, + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["list"] + } + ] + }, + "/{filesystem}?restype=container&comp=list&hierarchy": { + "get": { + "tags": ["containers"], + "produces": ["application/xml"], + "operationId": "FileSystem_ListBlobHierarchySegment", + "description": "The List Blobs operation returns a list of the blobs under the specified container", + "parameters": [ + { + "$ref": "#/parameters/Prefix" + }, + { + "$ref": "#/parameters/Delimiter" + }, + { + "$ref": "#/parameters/Marker" + }, + { + "$ref": "#/parameters/MaxResults" + }, + { + "$ref": "#/parameters/MaxResultsBlob" + }, + { + "$ref": "#/parameters/ListBlobsInclude" + }, + { + "$ref": "#/parameters/ListBlobsShowOnly" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "Success.", + "headers": { + "Content-Type": { + "type": "string", + "description": "The media type of the body of the response. For List Blobs this is 'application/xml'" + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated" + } + }, + "schema": { + "$ref": "#/definitions/ListBlobsHierarchySegmentResponse" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "NextMarker" + } + }, + "parameters": [ + { + "$ref": "#/parameters/FileSystem" + }, + { + "name": "restype", + "description": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": ["container"] + }, + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["list"] + } + ] + }, + "/{filesystem}/{path}": { + "put": { + "operationId": "Path_Create", + "summary": "Create File | Create Directory | Rename File | Rename Directory", + "description": "Create or rename a file or directory. By default, the destination is overwritten and if the destination already exists and has a lease the lease is broken. This operation supports conditional HTTP requests. For more information, see [Specifying Conditional Headers for Blob Service Operations](https://docs.microsoft.com/en-us/rest/api/storageservices/specifying-conditional-headers-for-blob-service-operations). To fail if the destination already exists, use a conditional request with If-None-Match: \"*\".", + "consumes": ["application/octet-stream"], + "tags": ["File and Directory Operations"], + "parameters": [ + { + "name": "resource", + "in": "query", + "description": "Required only for Create File and Create Directory. The value must be \"file\" or \"directory\".", + "required": false, + "type": "string", + "enum": ["directory", "file"], + "x-ms-enum": { + "name": "PathResourceType", + "modelAsString": false + } + }, + { + "$ref": "#/parameters/Continuation" + }, + { + "name": "mode", + "in": "query", + "description": "Optional. Valid only when namespace is enabled. This parameter determines the behavior of the rename operation. The value must be \"legacy\" or \"posix\", and the default value will be \"posix\".", + "required": false, + "type": "string", + "enum": ["legacy", "posix"], + "x-ms-enum": { + "name": "PathRenameMode", + "modelAsString": false + } + }, + { + "$ref": "#/parameters/CacheControl" + }, + { + "$ref": "#/parameters/ContentEncoding" + }, + { + "$ref": "#/parameters/ContentLanguage" + }, + { + "$ref": "#/parameters/ContentDisposition" + }, + { + "$ref": "#/parameters/ContentType" + }, + { + "$ref": "#/parameters/RenameSource" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/SourceLeaseId" + }, + { + "$ref": "#/parameters/Properties" + }, + { + "$ref": "#/parameters/Permissions" + }, + { + "$ref": "#/parameters/Umask" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/SourceIfMatch" + }, + { + "$ref": "#/parameters/SourceIfNoneMatch" + }, + { + "$ref": "#/parameters/SourceIfModifiedSince" + }, + { + "$ref": "#/parameters/SourceIfUnmodifiedSince" + }, + { + "$ref": "#/parameters/EncryptionKey" + }, + { + "$ref": "#/parameters/EncryptionKeySha256" + }, + { + "$ref": "#/parameters/EncryptionAlgorithm" + }, + { + "$ref": "#/parameters/Owner" + }, + { + "$ref": "#/parameters/Group" + }, + { + "$ref": "#/parameters/Acl" + }, + { + "$ref": "#/parameters/ProposedLeaseIdOptional" + }, + { + "$ref": "#/parameters/LeaseDurationMethod" + }, + { + "$ref": "#/parameters/PathExpiryOptionsOptional" + }, + { + "$ref": "#/parameters/PathExpiryTime" + } + ], + "responses": { + "201": { + "description": "The file or directory was created.", + "headers": { + "Date": { + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated.", + "type": "string", + "format": "date-time-rfc1123" + }, + "ETag": { + "description": "An HTTP entity tag associated with the file or directory.", + "type": "string" + }, + "Last-Modified": { + "description": "The data and time the file or directory was last modified. Write operations on the file or directory update the last modified time.", + "format": "date-time-rfc1123", + "type": "string" + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation.", + "pattern": "^[{(]?[0-9a-f]{8}[-]?([0-9a-f]{4}[-]?){3}[0-9a-f]{12}[)}]?$", + "type": "string" + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "description": "The version of the REST protocol used to process the request.", + "type": "string" + }, + "x-ms-continuation": { + "x-ms-client-name": "Continuation", + "description": "When renaming a directory, the number of paths that are renamed with each invocation is limited. If the number of paths to be renamed exceeds this limit, a continuation token is returned in this response header. When a continuation token is returned in the response, it must be specified in a subsequent invocation of the rename operation to continue renaming the directory.", + "type": "string" + }, + "Content-Length": { + "description": "The size of the resource in bytes.", + "type": "integer", + "format": "int64" + }, + "x-ms-request-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the contents of the request are successfully encrypted using the specified algorithm, and false otherwise." + }, + "x-ms-encryption-key-sha256": { + "x-ms-client-name": "EncryptionKeySha256", + "type": "string", + "description": "The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned when the blob was encrypted with a customer-provided key." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "patch": { + "operationId": "Path_Update", + "summary": "Append Data | Flush Data | Set Properties | Set Access Control", + "description": "Uploads data to be appended to a file, flushes (writes) previously uploaded data to a file, sets properties for a file or directory, or sets access control for a file or directory. Data can only be appended to a file. Concurrent writes to the same file using multiple clients are not supported. This operation supports conditional HTTP requests. For more information, see [Specifying Conditional Headers for Blob Service Operations](https://docs.microsoft.com/en-us/rest/api/storageservices/specifying-conditional-headers-for-blob-service-operations).", + "consumes": ["application/octet-stream"], + "tags": ["File and Directory Operations"], + "parameters": [ + { + "name": "action", + "in": "query", + "description": "The action must be \"append\" to upload data to be appended to a file, \"flush\" to flush previously uploaded data to a file, \"setProperties\" to set the properties of a file or directory, \"setAccessControl\" to set the owner, group, permissions, or access control list for a file or directory, or \"setAccessControlRecursive\" to set the access control list for a directory recursively. Note that Hierarchical Namespace must be enabled for the account in order to use access control. Also note that the Access Control List (ACL) includes permissions for the owner, owning group, and others, so the x-ms-permissions and x-ms-acl request headers are mutually exclusive.", + "required": true, + "type": "string", + "enum": [ + "append", + "flush", + "setProperties", + "setAccessControl", + "setAccessControlRecursive" + ], + "x-ms-enum": { + "name": "PathUpdateAction", + "modelAsString": false + } + }, + { + "name": "flush", + "in": "query", + "description": "Optional. Valid only for append calls. This parameter allows the caller to flush during an append call. Default value is 'false' , if 'true' the data will be flushed with the append call. Note that when using flush=true, the following headers are not supported - 'x-ms-cache-control', 'x-ms-content-encoding', 'x-ms-content-type', 'x-ms-content-language', 'x-ms-content-md5', 'x-ms-content-disposition'. To set these headers during flush, please use action=flush", + "required": false, + "type": "boolean" + }, + { + "name": "maxRecords", + "in": "query", + "description": "Optional. Valid for \"SetAccessControlRecursive\" operation. It specifies the maximum number of files or directories on which the acl change will be applied. If omitted or greater than 2,000, the request will process up to 2,000 items", + "format": "int32", + "minimum": 1, + "required": false, + "type": "integer" + }, + { + "name": "continuation", + "in": "query", + "description": "Optional. The number of paths processed with each invocation is limited. If the number of paths to be processed exceeds this limit, a continuation token is returned in the response header x-ms-continuation. When a continuation token is returned in the response, it must be percent-encoded and specified in a subsequent invocation of setAccessControlRecursive operation.", + "required": false, + "type": "string" + }, + { + "$ref": "#/parameters/PathSetAccessControlRecursiveMode" + }, + { + "$ref": "#/parameters/ForceFlag" + }, + { + "$ref": "#/parameters/Position" + }, + { + "$ref": "#/parameters/RetainUncommittedData" + }, + { + "$ref": "#/parameters/Close" + }, + { + "$ref": "#/parameters/ContentLength" + }, + { + "$ref": "#/parameters/ContentMD5" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/CacheControl" + }, + { + "$ref": "#/parameters/ContentType" + }, + { + "$ref": "#/parameters/ContentDisposition" + }, + { + "$ref": "#/parameters/ContentEncoding" + }, + { + "$ref": "#/parameters/ContentLanguage" + }, + { + "$ref": "#/parameters/Properties" + }, + { + "$ref": "#/parameters/Owner" + }, + { + "$ref": "#/parameters/Group" + }, + { + "$ref": "#/parameters/Permissions" + }, + { + "$ref": "#/parameters/Acl" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/Body" + } + ], + "responses": { + "200": { + "description": "The data was flushed (written) to the file or the properties were set successfully. Response body is optional and is valid only for \"SetAccessControlRecursive\"", + "headers": { + "Date": { + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated.", + "type": "string", + "format": "date-time-rfc1123" + }, + "ETag": { + "description": "An HTTP entity tag associated with the file or directory.", + "type": "string" + }, + "Last-Modified": { + "description": "The data and time the file or directory was last modified. Write operations on the file or directory update the last modified time.", + "format": "date-time-rfc1123", + "type": "string" + }, + "Accept-Ranges": { + "description": "Indicates that the service supports requests for partial file content.", + "type": "string" + }, + "Cache-Control": { + "description": "If the Cache-Control request header has previously been set for the resource, that value is returned in this header.", + "type": "string" + }, + "Content-Disposition": { + "description": "If the Content-Disposition request header has previously been set for the resource, that value is returned in this header.", + "type": "string" + }, + "Content-Encoding": { + "description": "If the Content-Encoding request header has previously been set for the resource, that value is returned in this header.", + "type": "string" + }, + "Content-Language": { + "description": "If the Content-Language request header has previously been set for the resource, that value is returned in this header.", + "type": "string" + }, + "Content-Length": { + "description": "The size of the resource in bytes.", + "type": "integer", + "format": "int64" + }, + "Content-Range": { + "description": "Indicates the range of bytes returned in the event that the client requested a subset of the file by setting the Range request header.", + "type": "string" + }, + "Content-Type": { + "description": "The content type specified for the resource. If no content type was specified, the default content type is application/octet-stream.", + "type": "string" + }, + "Content-MD5": { + "description": "An MD5 hash of the request content. This header is only returned for \"Flush\" operation. This header is returned so that the client can check for message content integrity. This header refers to the content of the request, not actual file content.", + "type": "string", + "format": "byte" + }, + "x-ms-properties": { + "x-ms-client-name": "Properties", + "description": "User-defined properties associated with the file or directory, in the format of a comma-separated list of name and value pairs \"n1=v1, n2=v2, ...\", where each value is a base64 encoded string. Note that the string may only contain ASCII characters in the ISO-8859-1 character set.", + "type": "string" + }, + "x-ms-continuation": { + "description": "When performing setAccessControlRecursive on a directory, the number of paths that are processed with each invocation is limited. If the number of paths to be processed exceeds this limit, a continuation token is returned in this response header. When a continuation token is returned in the response, it must be specified in a subsequent invocation of the setAccessControlRecursive operation to continue the setAccessControlRecursive operation on the directory.", + "type": "string" + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation.", + "pattern": "^[{(]?[0-9a-f]{8}[-]?([0-9a-f]{4}[-]?){3}[0-9a-f]{12}[)}]?$", + "type": "string" + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "description": "The version of the REST protocol used to process the request.", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/SetAccessControlRecursiveResponse" + } + }, + "202": { + "description": "The uploaded data was accepted.", + "headers": { + "Content-MD5": { + "description": "An MD5 hash of the request content. This header is only returned for \"Append\" operation. This header is returned so that the client can check for message content integrity. The value of this header is computed by the service; it is not necessarily the same value specified in the request headers.", + "type": "string", + "format": "byte" + }, + "Date": { + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated.", + "type": "string", + "format": "date-time-rfc1123" + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation.", + "pattern": "^[{(]?[0-9a-f]{8}[-]?([0-9a-f]{4}[-]?){3}[0-9a-f]{12}[)}]?$", + "type": "string" + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "description": "The version of the REST protocol used to process the request.", + "type": "string" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "post": { + "operationId": "Path_Lease", + "summary": "Lease Path", + "description": "Create and manage a lease to restrict write and delete access to the path. This operation supports conditional HTTP requests. For more information, see [Specifying Conditional Headers for Blob Service Operations](https://docs.microsoft.com/en-us/rest/api/storageservices/specifying-conditional-headers-for-blob-service-operations).", + "tags": ["File and Directory Operations"], + "parameters": [ + { + "name": "x-ms-lease-action", + "in": "header", + "description": "There are five lease actions: \"acquire\", \"break\", \"change\", \"renew\", and \"release\". Use \"acquire\" and specify the \"x-ms-proposed-lease-id\" and \"x-ms-lease-duration\" to acquire a new lease. Use \"break\" to break an existing lease. When a lease is broken, the lease break period is allowed to elapse, during which time no lease operation except break and release can be performed on the file. When a lease is successfully broken, the response indicates the interval in seconds until a new lease can be acquired. Use \"change\" and specify the current lease ID in \"x-ms-lease-id\" and the new lease ID in \"x-ms-proposed-lease-id\" to change the lease ID of an active lease. Use \"renew\" and specify the \"x-ms-lease-id\" to renew an existing lease. Use \"release\" and specify the \"x-ms-lease-id\" to release a lease.", + "required": true, + "type": "string", + "enum": ["acquire", "break", "change", "renew", "release"], + "x-ms-enum": { + "name": "PathLeaseAction", + "modelAsString": false + } + }, + { + "$ref": "#/parameters/LeaseDuration" + }, + { + "name": "x-ms-lease-break-period", + "in": "header", + "description": "The lease break period duration is optional to break a lease, and specifies the break period of the lease in seconds. The lease break duration must be between 0 and 60 seconds.", + "format": "int32", + "required": false, + "type": "integer" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/ProposedLeaseIdOptional" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + } + ], + "responses": { + "200": { + "description": "The \"renew\", \"change\" or \"release\" action was successful.", + "headers": { + "Date": { + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated.", + "type": "string", + "format": "date-time-rfc1123" + }, + "ETag": { + "description": "An HTTP entity tag associated with the file.", + "type": "string" + }, + "Last-Modified": { + "description": "The data and time the file was last modified. Write operations on the file update the last modified time.", + "format": "date-time-rfc1123", + "type": "string" + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation.", + "pattern": "^[{(]?[0-9a-f]{8}[-]?([0-9a-f]{4}[-]?){3}[0-9a-f]{12}[)}]?$", + "type": "string" + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "description": "The version of the REST protocol used to process the request.", + "type": "string" + }, + "x-ms-lease-id": { + "x-ms-client-name": "LeaseId", + "description": "A successful \"renew\" action returns the lease ID.", + "pattern": "^[{(]?[0-9a-f]{8}[-]?([0-9a-f]{4}[-]?){3}[0-9a-f]{12}[)}]?$", + "type": "string" + } + } + }, + "201": { + "description": "A new lease has been created. The \"acquire\" action was successful.", + "headers": { + "Date": { + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated.", + "type": "string", + "format": "date-time-rfc1123" + }, + "ETag": { + "description": "An HTTP entity tag associated with the file or directory.", + "type": "string" + }, + "Last-Modified": { + "description": "The data and time the file or directory was last modified. Write operations on the file or directory update the last modified time.", + "format": "date-time-rfc1123", + "type": "string" + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation.", + "pattern": "^[{(]?[0-9a-f]{8}[-]?([0-9a-f]{4}[-]?){3}[0-9a-f]{12}[)}]?$", + "type": "string" + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "description": "The version of the REST protocol used to process the request.", + "type": "string" + }, + "x-ms-lease-id": { + "x-ms-client-name": "LeaseId", + "description": "A successful \"acquire\" action returns the lease ID.", + "pattern": "^[{(]?[0-9a-f]{8}[-]?([0-9a-f]{4}[-]?){3}[0-9a-f]{12}[)}]?$", + "type": "string" + } + } + }, + "202": { + "description": "The \"break\" lease action was successful.", + "headers": { + "ETag": { + "description": "An HTTP entity tag associated with the file or directory.", + "type": "string" + }, + "Last-Modified": { + "description": "The data and time the file or directory was last modified. Write operations on the file or directory update the last modified time.", + "format": "date-time-rfc1123", + "type": "string" + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation.", + "pattern": "^[{(]?[0-9a-f]{8}[-]?([0-9a-f]{4}[-]?){3}[0-9a-f]{12}[)}]?$", + "type": "string" + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "description": "The version of the REST protocol used to process the request.", + "type": "string" + }, + "x-ms-lease-time": { + "x-ms-client-name": "LeaseTime", + "description": "The time remaining in the lease period in seconds.", + "type": "string" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "get": { + "operationId": "Path_Read", + "summary": "Read File", + "description": "Read the contents of a file. For read operations, range requests are supported. This operation supports conditional HTTP requests. For more information, see [Specifying Conditional Headers for Blob Service Operations](https://docs.microsoft.com/en-us/rest/api/storageservices/specifying-conditional-headers-for-blob-service-operations).", + "tags": ["File and Directory Operations"], + "parameters": [ + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "name": "x-ms-range-get-content-md5", + "in": "header", + "description": "Optional. When this header is set to \"true\" and specified together with the Range header, the service returns the MD5 hash for the range, as long as the range is less than or equal to 4MB in size. If this header is specified without the Range header, the service returns status code 400 (Bad Request). If this header is set to true when the range exceeds 4 MB in size, the service returns status code 400 (Bad Request).", + "required": false, + "type": "boolean" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/EncryptionKey" + }, + { + "$ref": "#/parameters/EncryptionKeySha256" + }, + { + "$ref": "#/parameters/EncryptionAlgorithm" + }, + { + "$ref": "#/parameters/Snapshot" + }, + { + "$ref": "#/parameters/VersionId" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/Range" + }, + { + "$ref": "#/parameters/GetRangeContentMD5" + }, + { + "$ref": "#/parameters/GetRangeContentCRC64" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "Ok", + "headers": { + "Accept-Ranges": { + "description": "Indicates that the service supports requests for partial file content.", + "type": "string" + }, + "Cache-Control": { + "description": "If the Cache-Control request header has previously been set for the resource, that value is returned in this header.", + "type": "string" + }, + "Content-Disposition": { + "description": "If the Content-Disposition request header has previously been set for the resource, that value is returned in this header.", + "type": "string" + }, + "Content-Encoding": { + "description": "If the Content-Encoding request header has previously been set for the resource, that value is returned in this header.", + "type": "string" + }, + "Content-Language": { + "description": "If the Content-Language request header has previously been set for the resource, that value is returned in this header.", + "type": "string" + }, + "Content-Length": { + "description": "The size of the resource in bytes.", + "type": "integer", + "format": "int64" + }, + "Content-Range": { + "description": "Indicates the range of bytes returned in the event that the client requested a subset of the file by setting the Range request header.", + "type": "string" + }, + "Content-Type": { + "description": "The content type specified for the resource. If no content type was specified, the default content type is application/octet-stream.", + "type": "string" + }, + "Content-MD5": { + "description": "The MD5 hash of complete file. If the file has an MD5 hash and this read operation is to read the complete file, this response header is returned so that the client can check for message content integrity.", + "type": "string", + "format": "byte" + }, + "Date": { + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated.", + "type": "string", + "format": "date-time-rfc1123" + }, + "ETag": { + "description": "An HTTP entity tag associated with the file or directory.", + "type": "string" + }, + "Last-Modified": { + "description": "The data and time the file or directory was last modified. Write operations on the file or directory update the last modified time.", + "format": "date-time-rfc1123", + "type": "string" + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation.", + "pattern": "^[{(]?[0-9a-f]{8}[-]?([0-9a-f]{4}[-]?){3}[0-9a-f]{12}[)}]?$", + "type": "string" + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "description": "The version of the REST protocol used to process the request.", + "type": "string" + }, + "x-ms-resource-type": { + "x-ms-client-name": "ResourceType", + "description": "The type of the resource. The value may be \"file\" or \"directory\". If not set, the value is \"file\".", + "type": "string" + }, + "x-ms-properties": { + "x-ms-client-name": "Properties", + "description": "The user-defined properties associated with the file or directory, in the format of a comma-separated list of name and value pairs \"n1=v1, n2=v2, ...\", where each value is a base64 encoded string. Note that the string may only contain ASCII characters in the ISO-8859-1 character set.", + "type": "string" + }, + "x-ms-lease-duration": { + "x-ms-client-name": "LeaseDuration", + "description": "When a resource is leased, specifies whether the lease is of infinite or fixed duration.", + "type": "string", + "enum": ["infinite", "fixed"], + "x-ms-enum": { + "name": "LeaseDurationType", + "modelAsString": false + } + }, + "x-ms-lease-state": { + "x-ms-client-name": "LeaseState", + "description": "Lease state of the resource.", + "type": "string", + "enum": [ + "available", + "leased", + "expired", + "breaking", + "broken" + ], + "x-ms-enum": { + "name": "LeaseStateType", + "modelAsString": false + } + }, + "x-ms-lease-status": { + "x-ms-client-name": "LeaseStatus", + "description": "The lease status of the resource.", + "type": "string", + "enum": ["locked", "unlocked"], + "x-ms-enum": { + "name": "LeaseStatusType", + "modelAsString": false + } + }, + "x-ms-request-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the contents of the request are successfully encrypted using the specified algorithm, and false otherwise." + }, + "x-ms-encryption-key-sha256": { + "x-ms-client-name": "EncryptionKeySha256", + "type": "string", + "description": "The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned when the blob was encrypted with a customer-provided key." + }, + "x-ms-meta": { + "type": "string", + "x-ms-client-name": "Metadata", + "x-ms-header-collection-prefix": "x-ms-meta-" + }, + "x-ms-creation-time": { + "x-ms-client-name": "CreationTime", + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the blob was created." + }, + "x-ms-or-policy-id": { + "x-ms-client-name": "ObjectReplicationPolicyId", + "type": "string", + "description": "Optional. Only valid when Object Replication is enabled for the storage container and on the destination blob of the replication." + }, + "x-ms-or": { + "type": "string", + "x-ms-client-name": "ObjectReplicationRules", + "x-ms-header-collection-prefix": "x-ms-or-", + "description": "Optional. Only valid when Object Replication is enabled for the storage container and on the source blob of the replication. When retrieving this header, it will return the header with the policy id and rule id (e.g. x-ms-or-policyid_ruleid), and the value will be the status of the replication (e.g. complete, failed)." + }, + "x-ms-blob-sequence-number": { + "x-ms-client-name": "BlobSequenceNumber", + "type": "integer", + "format": "int64", + "description": "The current sequence number for a page blob. This header is not returned for block blobs or append blobs" + }, + "x-ms-blob-type": { + "x-ms-client-name": "BlobType", + "description": "The blob's type.", + "type": "string", + "enum": ["BlockBlob", "PageBlob", "AppendBlob"], + "x-ms-enum": { + "name": "BlobType", + "modelAsString": false + } + }, + "x-ms-copy-completion-time": { + "x-ms-client-name": "CopyCompletionTime", + "type": "string", + "format": "date-time-rfc1123", + "description": "Conclusion time of the last attempted Copy Blob operation where this blob was the destination blob. This value can specify the time of a completed, aborted, or failed copy attempt. This header does not appear if a copy is pending, if this blob has never been the destination in a Copy Blob operation, or if this blob has been modified after a concluded Copy Blob operation using Set Blob Properties, Put Blob, or Put Block List." + }, + "x-ms-copy-status-description": { + "x-ms-client-name": "CopyStatusDescription", + "type": "string", + "description": "Only appears when x-ms-copy-status is failed or pending. Describes the cause of the last fatal or non-fatal copy operation failure. This header does not appear if this blob has never been the destination in a Copy Blob operation, or if this blob has been modified after a concluded Copy Blob operation using Set Blob Properties, Put Blob, or Put Block List" + }, + "x-ms-copy-id": { + "x-ms-client-name": "CopyId", + "type": "string", + "description": "String identifier for this copy operation. Use with Get Blob Properties to check the status of this copy operation, or pass to Abort Copy Blob to abort a pending copy." + }, + "x-ms-copy-progress": { + "x-ms-client-name": "CopyProgress", + "type": "string", + "description": "Contains the number of bytes copied and the total bytes in the source in the last attempted Copy Blob operation where this blob was the destination blob. Can show between 0 and Content-Length bytes copied. This header does not appear if this blob has never been the destination in a Copy Blob operation, or if this blob has been modified after a concluded Copy Blob operation using Set Blob Properties, Put Blob, or Put Block List" + }, + "x-ms-copy-source": { + "x-ms-client-name": "CopySource", + "type": "string", + "description": "URL up to 2 KB in length that specifies the source blob or file used in the last attempted Copy Blob operation where this blob was the destination blob. This header does not appear if this blob has never been the destination in a Copy Blob operation, or if this blob has been modified after a concluded Copy Blob operation using Set Blob Properties, Put Blob, or Put Block List." + }, + "x-ms-copy-status": { + "x-ms-client-name": "CopyStatus", + "description": "State of the copy operation identified by x-ms-copy-id.", + "type": "string", + "enum": ["pending", "success", "aborted", "failed"], + "x-ms-enum": { + "name": "CopyStatusType", + "modelAsString": false + } + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-version-id": { + "x-ms-client-name": "VersionId", + "type": "string", + "description": "A DateTime value returned by the service that uniquely identifies the blob. The value of this header indicates the blob version, and may be used in subsequent requests to access this version of the blob." + }, + "x-ms-is-current-version": { + "x-ms-client-name": "IsCurrentVersion", + "type": "boolean", + "description": "The value of this header indicates whether version of this blob is a current version, see also x-ms-version-id header." + }, + "x-ms-blob-committed-block-count": { + "x-ms-client-name": "BlobCommittedBlockCount", + "type": "integer", + "description": "The number of committed blocks present in the blob. This header is returned only for append blobs." + }, + "x-ms-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the blob data and application metadata are completely encrypted using the specified algorithm. Otherwise, the value is set to false (when the blob is unencrypted, or if only parts of the blob/application metadata are encrypted)." + }, + "x-ms-encryption-scope": { + "x-ms-client-name": "EncryptionScope", + "type": "string", + "description": "Returns the name of the encryption scope used to encrypt the blob contents and application metadata. Note that the absence of this header implies use of the default account encryption scope." + }, + "x-ms-blob-content-md5": { + "x-ms-client-name": "BlobContentMD5", + "type": "string", + "format": "byte", + "description": "If the blob has a MD5 hash, and if request contains range header (Range or x-ms-range), this response header is returned with the value of the whole blob's MD5 value. This value may or may not be equal to the value returned in Content-MD5 header, with the latter calculated from the requested range" + }, + "x-ms-tag-count": { + "x-ms-client-name": "TagCount", + "type": "integer", + "format": "int64", + "description": "The number of tags associated with the blob" + }, + "x-ms-blob-sealed": { + "x-ms-client-name": "IsSealed", + "type": "boolean", + "description": "If this blob has been sealed" + }, + "x-ms-last-access-time": { + "x-ms-client-name": "LastAccessed", + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the blob was last read or written to" + }, + "x-ms-immutability-policy-until-date": { + "x-ms-client-name": "ImmutabilityPolicyExpiresOn", + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the blob immutability policy will expire." + }, + "x-ms-immutability-policy-mode": { + "x-ms-client-name": "ImmutabilityPolicyMode", + "type": "string", + "enum": ["Mutable", "Unlocked", "Locked"], + "x-ms-enum": { + "name": "BlobImmutabilityPolicyMode", + "modelAsString": false + }, + "description": "Indicates immutability policy mode." + }, + "x-ms-legal-hold": { + "x-ms-client-name": "LegalHold", + "type": "boolean", + "description": "Indicates if a legal hold is present on the blob." + } + }, + "schema": { + "type": "object", + "format": "file" + } + }, + "206": { + "description": "Partial content", + "headers": { + "Accept-Ranges": { + "description": "Indicates that the service supports requests for partial file content.", + "type": "string" + }, + "Cache-Control": { + "description": "If the Cache-Control request header has previously been set for the resource, that value is returned in this header.", + "type": "string" + }, + "Content-Disposition": { + "description": "If the Content-Disposition request header has previously been set for the resource, that value is returned in this header.", + "type": "string" + }, + "Content-Encoding": { + "description": "If the Content-Encoding request header has previously been set for the resource, that value is returned in this header.", + "type": "string" + }, + "Content-Language": { + "description": "If the Content-Language request header has previously been set for the resource, that value is returned in this header.", + "type": "string" + }, + "Content-Length": { + "description": "The size of the resource in bytes.", + "type": "integer", + "format": "int64" + }, + "Content-Range": { + "description": "Indicates the range of bytes returned in the event that the client requested a subset of the file by setting the Range request header.", + "type": "string" + }, + "Content-Type": { + "description": "The content type specified for the resource. If no content type was specified, the default content type is application/octet-stream.", + "type": "string" + }, + "Content-MD5": { + "description": "The MD5 hash of read range. If the request is to read a specified range and the \"x-ms-range-get-content-md5\" is set to true, then the request returns an MD5 hash for the range, as long as the range size is less than or equal to 4 MB.", + "type": "string", + "format": "byte" + }, + "x-ms-content-md5": { + "description": "The MD5 hash of complete file stored in storage. If the file has a MD5 hash, and if request contains range header (Range or x-ms-range), this response header is returned with the value of the complete file's MD5 value. This value may or may not be equal to the value returned in Content-MD5 header, with the latter calculated from the requested range.", + "type": "string", + "format": "byte" + }, + "Date": { + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated.", + "type": "string", + "format": "date-time-rfc1123" + }, + "ETag": { + "description": "An HTTP entity tag associated with the file or directory.", + "type": "string" + }, + "Last-Modified": { + "description": "The data and time the file or directory was last modified. Write operations on the file or directory update the last modified time.", + "format": "date-time-rfc1123", + "type": "string" + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation.", + "pattern": "^[{(]?[0-9a-f]{8}[-]?([0-9a-f]{4}[-]?){3}[0-9a-f]{12}[)}]?$", + "type": "string" + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "description": "The version of the REST protocol used to process the request.", + "type": "string" + }, + "x-ms-resource-type": { + "x-ms-client-name": "ResourceType", + "description": "The type of the resource. The value may be \"file\" or \"directory\". If not set, the value is \"file\".", + "type": "string" + }, + "x-ms-properties": { + "x-ms-client-name": "Properties", + "description": "The user-defined properties associated with the file or directory, in the format of a comma-separated list of name and value pairs \"n1=v1, n2=v2, ...\", where each value is a base64 encoded string. Note that the string may only contain ASCII characters in the ISO-8859-1 character set.", + "type": "string" + }, + "x-ms-lease-duration": { + "x-ms-client-name": "LeaseDuration", + "description": "When a resource is leased, specifies whether the lease is of infinite or fixed duration.", + "type": "string", + "enum": ["infinite", "fixed"], + "x-ms-enum": { + "name": "LeaseDurationType", + "modelAsString": false + } + }, + "x-ms-lease-state": { + "x-ms-client-name": "LeaseState", + "description": "Lease state of the resource. ", + "type": "string", + "enum": [ + "available", + "leased", + "expired", + "breaking", + "broken" + ], + "x-ms-enum": { + "name": "LeaseStateType", + "modelAsString": false + } + }, + "x-ms-lease-status": { + "x-ms-client-name": "LeaseStatus", + "description": "The lease status of the resource.", + "type": "string", + "enum": ["locked", "unlocked"], + "x-ms-enum": { + "name": "LeaseStatusType", + "modelAsString": false + } + }, + "x-ms-request-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the contents of the request are successfully encrypted using the specified algorithm, and false otherwise." + }, + "x-ms-encryption-key-sha256": { + "x-ms-client-name": "EncryptionKeySha256", + "type": "string", + "description": "The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned when the blob was encrypted with a customer-provided key." + }, + "x-ms-meta": { + "type": "string", + "x-ms-client-name": "Metadata", + "x-ms-header-collection-prefix": "x-ms-meta-" + }, + "x-ms-or-policy-id": { + "x-ms-client-name": "ObjectReplicationPolicyId", + "type": "string", + "description": "Optional. Only valid when Object Replication is enabled for the storage container and on the destination blob of the replication." + }, + "x-ms-or": { + "type": "string", + "x-ms-client-name": "ObjectReplicationRules", + "x-ms-header-collection-prefix": "x-ms-or-", + "description": "Optional. Only valid when Object Replication is enabled for the storage container and on the source blob of the replication. When retrieving this header, it will return the header with the policy id and rule id (e.g. x-ms-or-policyid_ruleid), and the value will be the status of the replication (e.g. complete, failed)." + }, + "x-ms-blob-sequence-number": { + "x-ms-client-name": "BlobSequenceNumber", + "type": "integer", + "format": "int64", + "description": "The current sequence number for a page blob. This header is not returned for block blobs or append blobs" + }, + "x-ms-blob-type": { + "x-ms-client-name": "BlobType", + "description": "The blob's type.", + "type": "string", + "enum": ["BlockBlob", "PageBlob", "AppendBlob"], + "x-ms-enum": { + "name": "BlobType", + "modelAsString": false + } + }, + "x-ms-content-crc64": { + "x-ms-client-name": "ContentCrc64", + "type": "string", + "format": "byte", + "description": "If the request is to read a specified range and the x-ms-range-get-content-crc64 is set to true, then the request returns a crc64 for the range, as long as the range size is less than or equal to 4 MB. If both x-ms-range-get-content-crc64 & x-ms-range-get-content-md5 is specified in the same request, it will fail with 400(Bad Request)" + }, + "x-ms-copy-completion-time": { + "x-ms-client-name": "CopyCompletionTime", + "type": "string", + "format": "date-time-rfc1123", + "description": "Conclusion time of the last attempted Copy Blob operation where this blob was the destination blob. This value can specify the time of a completed, aborted, or failed copy attempt. This header does not appear if a copy is pending, if this blob has never been the destination in a Copy Blob operation, or if this blob has been modified after a concluded Copy Blob operation using Set Blob Properties, Put Blob, or Put Block List." + }, + "x-ms-copy-status-description": { + "x-ms-client-name": "CopyStatusDescription", + "type": "string", + "description": "Only appears when x-ms-copy-status is failed or pending. Describes the cause of the last fatal or non-fatal copy operation failure. This header does not appear if this blob has never been the destination in a Copy Blob operation, or if this blob has been modified after a concluded Copy Blob operation using Set Blob Properties, Put Blob, or Put Block List" + }, + "x-ms-copy-id": { + "x-ms-client-name": "CopyId", + "type": "string", + "description": "String identifier for this copy operation. Use with Get Blob Properties to check the status of this copy operation, or pass to Abort Copy Blob to abort a pending copy." + }, + "x-ms-copy-progress": { + "x-ms-client-name": "CopyProgress", + "type": "string", + "description": "Contains the number of bytes copied and the total bytes in the source in the last attempted Copy Blob operation where this blob was the destination blob. Can show between 0 and Content-Length bytes copied. This header does not appear if this blob has never been the destination in a Copy Blob operation, or if this blob has been modified after a concluded Copy Blob operation using Set Blob Properties, Put Blob, or Put Block List" + }, + "x-ms-copy-source": { + "x-ms-client-name": "CopySource", + "type": "string", + "description": "URL up to 2 KB in length that specifies the source blob or file used in the last attempted Copy Blob operation where this blob was the destination blob. This header does not appear if this blob has never been the destination in a Copy Blob operation, or if this blob has been modified after a concluded Copy Blob operation using Set Blob Properties, Put Blob, or Put Block List." + }, + "x-ms-copy-status": { + "x-ms-client-name": "CopyStatus", + "description": "State of the copy operation identified by x-ms-copy-id.", + "type": "string", + "enum": ["pending", "success", "aborted", "failed"], + "x-ms-enum": { + "name": "CopyStatusType", + "modelAsString": false + } + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-version-id": { + "x-ms-client-name": "VersionId", + "type": "string", + "description": "A DateTime value returned by the service that uniquely identifies the blob. The value of this header indicates the blob version, and may be used in subsequent requests to access this version of the blob." + }, + "x-ms-is-current-version": { + "x-ms-client-name": "IsCurrentVersion", + "type": "boolean", + "description": "The value of this header indicates whether version of this blob is a current version, see also x-ms-version-id header." + }, + "x-ms-blob-committed-block-count": { + "x-ms-client-name": "BlobCommittedBlockCount", + "type": "integer", + "description": "The number of committed blocks present in the blob. This header is returned only for append blobs." + }, + "x-ms-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the blob data and application metadata are completely encrypted using the specified algorithm. Otherwise, the value is set to false (when the blob is unencrypted, or if only parts of the blob/application metadata are encrypted)." + }, + "x-ms-encryption-scope": { + "x-ms-client-name": "EncryptionScope", + "type": "string", + "description": "Returns the name of the encryption scope used to encrypt the blob contents and application metadata. Note that the absence of this header implies use of the default account encryption scope." + }, + "x-ms-blob-content-md5": { + "x-ms-client-name": "BlobContentMD5", + "type": "string", + "format": "byte", + "description": "If the blob has a MD5 hash, and if request contains range header (Range or x-ms-range), this response header is returned with the value of the whole blob's MD5 value. This value may or may not be equal to the value returned in Content-MD5 header, with the latter calculated from the requested range" + }, + "x-ms-tag-count": { + "x-ms-client-name": "TagCount", + "type": "integer", + "format": "int64", + "description": "The number of tags associated with the blob" + }, + "x-ms-blob-sealed": { + "x-ms-client-name": "IsSealed", + "type": "boolean", + "description": "If this blob has been sealed" + }, + "x-ms-last-access-time": { + "x-ms-client-name": "LastAccessed", + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the blob was last read or written to" + }, + "x-ms-immutability-policy-until-date": { + "x-ms-client-name": "ImmutabilityPolicyExpiresOn", + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the blob immutability policy will expire." + }, + "x-ms-immutability-policy-mode": { + "x-ms-client-name": "ImmutabilityPolicyMode", + "type": "string", + "description": "Indicates immutability policy mode." + }, + "x-ms-legal-hold": { + "x-ms-client-name": "LegalHold", + "type": "boolean", + "description": "Indicates if a legal hold is present on the blob." + } + }, + "schema": { + "type": "object", + "format": "file" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "head": { + "operationId": "Path_GetProperties", + "summary": "Get Properties | Get Status | Get Access Control List", + "description": "Get Properties returns all system and user defined properties for a path. Get Status returns all system defined properties for a path. Get Access Control List returns the access control list for a path. This operation supports conditional HTTP requests. For more information, see [Specifying Conditional Headers for Blob Service Operations](https://docs.microsoft.com/en-us/rest/api/storageservices/specifying-conditional-headers-for-blob-service-operations).", + "tags": ["File and Directory Operations"], + "parameters": [ + { + "name": "action", + "in": "query", + "description": "Optional. If the value is \"getStatus\" only the system defined properties for the path are returned. If the value is \"getAccessControl\" the access control list is returned in the response headers (Hierarchical Namespace must be enabled for the account), otherwise the properties are returned.", + "required": false, + "type": "string", + "enum": ["getAccessControl", "getStatus"], + "x-ms-enum": { + "name": "PathGetPropertiesAction", + "modelAsString": false + } + }, + { + "$ref": "#/parameters/Upn" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/Snapshot" + }, + { + "$ref": "#/parameters/VersionId" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/EncryptionKey" + }, + { + "$ref": "#/parameters/EncryptionKeySha256" + }, + { + "$ref": "#/parameters/EncryptionAlgorithm" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "Returns all properties for the file or directory.", + "headers": { + "Accept-Ranges": { + "description": "Indicates that the service supports requests for partial file content.", + "type": "string" + }, + "Cache-Control": { + "description": "If the Cache-Control request header has previously been set for the resource, that value is returned in this header.", + "type": "string" + }, + "Content-Disposition": { + "description": "If the Content-Disposition request header has previously been set for the resource, that value is returned in this header.", + "type": "string" + }, + "Content-Encoding": { + "description": "If the Content-Encoding request header has previously been set for the resource, that value is returned in this header.", + "type": "string" + }, + "Content-Language": { + "description": "If the Content-Language request header has previously been set for the resource, that value is returned in this header.", + "type": "string" + }, + "Content-Length": { + "description": "The size of the resource in bytes.", + "type": "integer", + "format": "int64" + }, + "Content-Range": { + "description": "Indicates the range of bytes returned in the event that the client requested a subset of the file by setting the Range request header.", + "type": "string" + }, + "Content-Type": { + "description": "The content type specified for the resource. If no content type was specified, the default content type is application/octet-stream.", + "type": "string" + }, + "Content-MD5": { + "description": "The MD5 hash of complete file stored in storage. This header is returned only for \"GetProperties\" operation. If the Content-MD5 header has been set for the file, this response header is returned for GetProperties call so that the client can check for message content integrity.", + "type": "string", + "format": "byte" + }, + "Date": { + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated.", + "type": "string", + "format": "date-time-rfc1123" + }, + "ETag": { + "description": "An HTTP entity tag associated with the file or directory.", + "type": "string" + }, + "Last-Modified": { + "description": "The data and time the file or directory was last modified. Write operations on the file or directory update the last modified time.", + "format": "date-time-rfc1123", + "type": "string" + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation.", + "pattern": "^[{(]?[0-9a-f]{8}[-]?([0-9a-f]{4}[-]?){3}[0-9a-f]{12}[)}]?$", + "type": "string" + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "description": "The version of the REST protocol used to process the request.", + "type": "string" + }, + "x-ms-resource-type": { + "x-ms-client-name": "ResourceType", + "description": "The type of the resource. The value may be \"file\" or \"directory\". If not set, the value is \"file\".", + "type": "string" + }, + "x-ms-properties": { + "x-ms-client-name": "Properties", + "description": "The user-defined properties associated with the file or directory, in the format of a comma-separated list of name and value pairs \"n1=v1, n2=v2, ...\", where each value is a base64 encoded string. Note that the string may only contain ASCII characters in the ISO-8859-1 character set.", + "type": "string" + }, + "x-ms-owner": { + "x-ms-client-name": "Owner", + "description": "The owner of the file or directory. Included in the response if Hierarchical Namespace is enabled for the account.", + "type": "string" + }, + "x-ms-group": { + "x-ms-client-name": "Group", + "description": "The owning group of the file or directory. Included in the response if Hierarchical Namespace is enabled for the account.", + "type": "string" + }, + "x-ms-permissions": { + "x-ms-client-name": "Permissions", + "description": "The POSIX access permissions for the file owner, the file owning group, and others. Included in the response if Hierarchical Namespace is enabled for the account.", + "type": "string" + }, + "x-ms-acl": { + "x-ms-client-name": "ACL", + "description": "The POSIX access control list for the file or directory. Included in the response only if the action is \"getAccessControl\" and Hierarchical Namespace is enabled for the account.", + "type": "string" + }, + "x-ms-lease-duration": { + "x-ms-client-name": "LeaseDuration", + "description": "When a resource is leased, specifies whether the lease is of infinite or fixed duration.", + "type": "string", + "enum": ["infinite", "fixed"], + "x-ms-enum": { + "name": "LeaseDurationType", + "modelAsString": false + } + }, + "x-ms-lease-state": { + "x-ms-client-name": "LeaseState", + "description": "Lease state of the resource.", + "type": "string", + "enum": [ + "available", + "leased", + "expired", + "breaking", + "broken" + ], + "x-ms-enum": { + "name": "LeaseStateType", + "modelAsString": false + } + }, + "x-ms-lease-status": { + "x-ms-client-name": "LeaseStatus", + "description": "The lease status of the resource.", + "type": "string", + "enum": ["locked", "unlocked"], + "x-ms-enum": { + "name": "LeaseStatusType", + "modelAsString": false + } + }, + "x-ms-meta": { + "type": "string", + "x-ms-client-name": "Metadata", + "x-ms-header-collection-prefix": "x-ms-meta-" + }, + "x-ms-creation-time": { + "x-ms-client-name": "CreationTime", + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the blob was created." + }, + "x-ms-or-policy-id": { + "x-ms-client-name": "ObjectReplicationPolicyId", + "type": "string", + "description": "Optional. Only valid when Object Replication is enabled for the storage container and on the destination blob of the replication." + }, + "x-ms-or": { + "type": "string", + "x-ms-client-name": "ObjectReplicationRules", + "x-ms-header-collection-prefix": "x-ms-or-", + "description": "Optional. Only valid when Object Replication is enabled for the storage container and on the source blob of the replication. When retrieving this header, it will return the header with the policy id and rule id (e.g. x-ms-or-policyid_ruleid), and the value will be the status of the replication (e.g. complete, failed)." + }, + "x-ms-blob-type": { + "x-ms-client-name": "BlobType", + "description": "The blob's type.", + "type": "string", + "enum": ["BlockBlob", "PageBlob", "AppendBlob"], + "x-ms-enum": { + "name": "BlobType", + "modelAsString": false + } + }, + "x-ms-copy-completion-time": { + "x-ms-client-name": "CopyCompletionTime", + "type": "string", + "format": "date-time-rfc1123", + "description": "Conclusion time of the last attempted Copy Blob operation where this blob was the destination blob. This value can specify the time of a completed, aborted, or failed copy attempt. This header does not appear if a copy is pending, if this blob has never been the destination in a Copy Blob operation, or if this blob has been modified after a concluded Copy Blob operation using Set Blob Properties, Put Blob, or Put Block List." + }, + "x-ms-copy-status-description": { + "x-ms-client-name": "CopyStatusDescription", + "type": "string", + "description": "Only appears when x-ms-copy-status is failed or pending. Describes the cause of the last fatal or non-fatal copy operation failure. This header does not appear if this blob has never been the destination in a Copy Blob operation, or if this blob has been modified after a concluded Copy Blob operation using Set Blob Properties, Put Blob, or Put Block List" + }, + "x-ms-copy-id": { + "x-ms-client-name": "CopyId", + "type": "string", + "description": "String identifier for this copy operation. Use with Get Blob Properties to check the status of this copy operation, or pass to Abort Copy Blob to abort a pending copy." + }, + "x-ms-copy-progress": { + "x-ms-client-name": "CopyProgress", + "type": "string", + "description": "Contains the number of bytes copied and the total bytes in the source in the last attempted Copy Blob operation where this blob was the destination blob. Can show between 0 and Content-Length bytes copied. This header does not appear if this blob has never been the destination in a Copy Blob operation, or if this blob has been modified after a concluded Copy Blob operation using Set Blob Properties, Put Blob, or Put Block List" + }, + "x-ms-copy-source": { + "x-ms-client-name": "CopySource", + "type": "string", + "description": "URL up to 2 KB in length that specifies the source blob or file used in the last attempted Copy Blob operation where this blob was the destination blob. This header does not appear if this blob has never been the destination in a Copy Blob operation, or if this blob has been modified after a concluded Copy Blob operation using Set Blob Properties, Put Blob, or Put Block List." + }, + "x-ms-copy-status": { + "x-ms-client-name": "CopyStatus", + "description": "State of the copy operation identified by x-ms-copy-id.", + "type": "string", + "enum": ["pending", "success", "aborted", "failed"], + "x-ms-enum": { + "name": "CopyStatusType", + "modelAsString": false + } + }, + "x-ms-incremental-copy": { + "x-ms-client-name": "IsIncrementalCopy", + "type": "boolean", + "description": "Included if the blob is incremental copy blob." + }, + "x-ms-copy-destination-snapshot": { + "x-ms-client-name": "DestinationSnapshot", + "type": "string", + "description": "Included if the blob is incremental copy blob or incremental copy snapshot, if x-ms-copy-status is success. Snapshot time of the last successful incremental copy snapshot for this blob." + }, + "x-ms-blob-sequence-number": { + "x-ms-client-name": "BlobSequenceNumber", + "type": "integer", + "format": "int64", + "description": "The current sequence number for a page blob. This header is not returned for block blobs or append blobs" + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-blob-committed-block-count": { + "x-ms-client-name": "BlobCommittedBlockCount", + "type": "integer", + "description": "The number of committed blocks present in the blob. This header is returned only for append blobs." + }, + "x-ms-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the blob data and application metadata are completely encrypted using the specified algorithm. Otherwise, the value is set to false (when the blob is unencrypted, or if only parts of the blob/application metadata are encrypted)." + }, + "x-ms-encryption-key-sha256": { + "x-ms-client-name": "EncryptionKeySha256", + "type": "string", + "description": "The SHA-256 hash of the encryption key used to encrypt the metadata. This header is only returned when the metadata was encrypted with a customer-provided key." + }, + "x-ms-encryption-scope": { + "x-ms-client-name": "EncryptionScope", + "type": "string", + "description": "Returns the name of the encryption scope used to encrypt the blob contents and application metadata. Note that the absence of this header implies use of the default account encryption scope." + }, + "x-ms-access-tier": { + "x-ms-client-name": "AccessTier", + "type": "string", + "description": "The tier of page blob on a premium storage account or tier of block blob on blob storage LRS accounts. For a list of allowed premium page blob tiers, see https://docs.microsoft.com/en-us/azure/virtual-machines/windows/premium-storage#features. For blob storage LRS accounts, valid values are Hot/Cool/Archive." + }, + "x-ms-access-tier-inferred": { + "x-ms-client-name": "AccessTierInferred", + "type": "boolean", + "description": "For page blobs on a premium storage account only. If the access tier is not explicitly set on the blob, the tier is inferred based on its content length and this header will be returned with true value." + }, + "x-ms-archive-status": { + "x-ms-client-name": "ArchiveStatus", + "type": "string", + "description": "For blob storage LRS accounts, valid values are rehydrate-pending-to-hot/rehydrate-pending-to-cool. If the blob is being rehydrated and is not complete then this header is returned indicating that rehydrate is pending and also tells the destination tier." + }, + "x-ms-access-tier-change-time": { + "x-ms-client-name": "AccessTierChangeTime", + "type": "string", + "format": "date-time-rfc1123", + "description": "The time the tier was changed on the object. This is only returned if the tier on the block blob was ever set." + }, + "x-ms-version-id": { + "x-ms-client-name": "VersionId", + "type": "string", + "description": "A DateTime value returned by the service that uniquely identifies the blob. The value of this header indicates the blob version, and may be used in subsequent requests to access this version of the blob." + }, + "x-ms-is-current-version": { + "x-ms-client-name": "IsCurrentVersion", + "type": "boolean", + "description": "The value of this header indicates whether version of this blob is a current version, see also x-ms-version-id header." + }, + "x-ms-tag-count": { + "x-ms-client-name": "TagCount", + "type": "integer", + "format": "int64", + "description": "The number of tags associated with the blob" + }, + "x-ms-expiry-time": { + "x-ms-client-name": "ExpiresOn", + "type": "string", + "format": "date-time-rfc1123", + "description": "The time this blob will expire." + }, + "x-ms-blob-sealed": { + "x-ms-client-name": "IsSealed", + "type": "boolean", + "description": "If this blob has been sealed" + }, + "x-ms-rehydrate-priority": { + "x-ms-client-name": "RehydratePriority", + "description": "If an object is in rehydrate pending state then this header is returned with priority of rehydrate. Valid values are High and Standard.", + "type": "string" + }, + "x-ms-last-access-time": { + "x-ms-client-name": "LastAccessed", + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the blob was last read or written to" + }, + "x-ms-immutability-policy-until-date": { + "x-ms-client-name": "ImmutabilityPolicyExpiresOn", + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the blob immutability policy will expire." + }, + "x-ms-immutability-policy-mode": { + "x-ms-client-name": "ImmutabilityPolicyMode", + "type": "string", + "enum": ["Mutable", "Unlocked", "Locked"], + "x-ms-enum": { + "name": "BlobImmutabilityPolicyMode", + "modelAsString": false + }, + "description": "Indicates immutability policy mode." + }, + "x-ms-legal-hold": { + "x-ms-client-name": "LegalHold", + "type": "boolean", + "description": "Indicates if a legal hold is present on the blob." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "delete": { + "operationId": "Path_Delete", + "summary": "Delete File | Delete Directory", + "description": "Delete the file or directory. This operation supports conditional HTTP requests. For more information, see [Specifying Conditional Headers for Blob Service Operations](https://docs.microsoft.com/en-us/rest/api/storageservices/specifying-conditional-headers-for-blob-service-operations).", + "tags": ["File and Directory Operations", "blob"], + "parameters": [ + { + "$ref": "#/parameters/RecursiveOptional" + }, + { + "$ref": "#/parameters/Continuation" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/Snapshot" + }, + { + "$ref": "#/parameters/VersionId" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/DeleteSnapshots" + }, + { + "$ref": "#/parameters/IfTags" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/BlobDeleteType" + } + ], + "responses": { + "200": { + "description": "The file was deleted.", + "headers": { + "Date": { + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated.", + "type": "string", + "format": "date-time-rfc1123" + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation.", + "pattern": "^[{(]?[0-9a-f]{8}[-]?([0-9a-f]{4}[-]?){3}[0-9a-f]{12}[)}]?$", + "type": "string" + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "description": "The version of the REST protocol used to process the request.", + "type": "string" + }, + "x-ms-continuation": { + "x-ms-client-name": "Continuation", + "description": "When deleting a directory, the number of paths that are deleted with each invocation is limited. If the number of paths to be deleted exceeds this limit, a continuation token is returned in this response header. When a continuation token is returned in the response, it must be specified in a subsequent invocation of the delete operation to continue deleting the directory.", + "type": "string" + }, + "x-ms-deletion-id": { + "x-ms-client-name": "DeletionId", + "description": "Returned only for hierarchical namespace space enabled accounts when soft delete is enabled. A unique identifier for the entity that can be used to restore it. See the Undelete REST API for more information.", + "type": "string" + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + } + } + }, + "202": { + "description": "The file was deleted.", + "headers": { + "Date": { + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated.", + "type": "string", + "format": "date-time-rfc1123" + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation.", + "pattern": "^[{(]?[0-9a-f]{8}[-]?([0-9a-f]{4}[-]?){3}[0-9a-f]{12}[)}]?$", + "type": "string" + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "description": "The version of the REST protocol used to process the request.", + "type": "string" + }, + "x-ms-continuation": { + "x-ms-client-name": "Continuation", + "description": "When deleting a directory, the number of paths that are deleted with each invocation is limited. If the number of paths to be deleted exceeds this limit, a continuation token is returned in this response header. When a continuation token is returned in the response, it must be specified in a subsequent invocation of the delete operation to continue deleting the directory.", + "type": "string" + }, + "x-ms-deletion-id": { + "x-ms-client-name": "DeletionId", + "description": "Returned only for hierarchical namespace space enabled accounts when soft delete is enabled. A unique identifier for the entity that can be used to restore it. See the Undelete REST API for more information.", + "type": "string" + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "$ref": "#/parameters/FileSystem" + }, + { + "$ref": "#/parameters/Path" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/Metadata" + } + ] + }, + "/{filesystem}/{path}?action=setAccessControl": { + "patch": { + "tags": ["directory"], + "operationId": "Path_SetAccessControl", + "description": "Set the owner, group, permissions, or access control list for a path.", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/Owner" + }, + { + "$ref": "#/parameters/Group" + }, + { + "$ref": "#/parameters/Permissions" + }, + { + "$ref": "#/parameters/Acl" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Set directory access control response.", + "headers": { + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + }, + "ETag": { + "type": "string", + "description": "An HTTP entity tag associated with the file or directory." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "The data and time the file or directory was last modified. Write operations on the file or directory update the last modified time." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "The version of the REST protocol used to process the request." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "The version of the REST protocol used to process the request." + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "$ref": "#/parameters/FileSystem" + }, + { + "$ref": "#/parameters/Path" + }, + { + "name": "action", + "description": "action", + "in": "query", + "required": true, + "type": "string", + "enum": ["setAccessControl"] + } + ] + }, + "/{filesystem}/{path}?action=setAccessControlRecursive": { + "patch": { + "tags": ["directory"], + "operationId": "Path_SetAccessControlRecursive", + "description": "Set the access control list for a path and sub-paths.", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/Continuation" + }, + { + "$ref": "#/parameters/PathSetAccessControlRecursiveMode" + }, + { + "$ref": "#/parameters/ForceFlag" + }, + { + "name": "maxRecords", + "in": "query", + "description": "Optional. It specifies the maximum number of files or directories on which the acl change will be applied. If omitted or greater than 2,000, the request will process up to 2,000 items", + "format": "int32", + "minimum": 1, + "required": false, + "type": "integer" + }, + { + "$ref": "#/parameters/Acl" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Set directory access control recursive response.", + "headers": { + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-continuation": { + "x-ms-client-name": "Continuation", + "description": "When performing setAccessControlRecursive on a directory, the number of paths that are processed with each invocation is limited. If the number of paths to be processed exceeds this limit, a continuation token is returned in this response header. When a continuation token is returned in the response, it must be specified in a subsequent invocation of the setAccessControlRecursive operation to continue the setAccessControlRecursive operation on the directory.", + "type": "string" + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "The version of the REST protocol used to process the request." + } + }, + "schema": { + "$ref": "#/definitions/SetAccessControlRecursiveResponse" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "The version of the REST protocol used to process the request." + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "$ref": "#/parameters/FileSystem" + }, + { + "$ref": "#/parameters/Path" + }, + { + "name": "action", + "description": "action", + "in": "query", + "required": true, + "type": "string", + "enum": ["setAccessControlRecursive"] + } + ] + }, + "/{filesystem}/{path}?action=setProperties": { + "patch": { + "operationId": "Path_SetProperties", + "summary": "Set Properties for file or directory", + "description": "Uploads data to be appended to a file, flushes (writes) previously uploaded data to a file, sets properties for a file or directory, or sets access control for a file or directory. Data can only be appended to a file. Concurrent writes to the same file using multiple clients are not supported. This operation supports conditional HTTP requests. For more information, see [Specifying Conditional Headers for Blob Service Operations](https://docs.microsoft.com/en-us/rest/api/storageservices/specifying-conditional-headers-for-blob-service-operations).", + "consumes": ["application/octet-stream"], + + "parameters": [ + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/CacheControl" + }, + { + "$ref": "#/parameters/ContentType" + }, + { + "$ref": "#/parameters/ContentDisposition" + }, + { + "$ref": "#/parameters/ContentEncoding" + }, + { + "$ref": "#/parameters/ContentLanguage" + }, + { + "$ref": "#/parameters/ContentMD5" + }, + { + "$ref": "#/parameters/Properties" + }, + { + "$ref": "#/parameters/Permissions" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "The properties were set successfully.", + "headers": { + "Date": { + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated.", + "type": "string", + "format": "date-time-rfc1123" + }, + "ETag": { + "description": "An HTTP entity tag associated with the file or directory.", + "type": "string" + }, + "Last-Modified": { + "description": "The data and time the file or directory was last modified. Write operations on the file or directory update the last modified time.", + "format": "date-time-rfc1123", + "type": "string" + }, + "Cache-Control": { + "description": "If the Cache-Control request header has previously been set for the resource, that value is returned in this header.", + "type": "string" + }, + "Content-Disposition": { + "description": "If the Content-Disposition request header has previously been set for the resource, that value is returned in this header.", + "type": "string" + }, + "Content-Encoding": { + "description": "If the Content-Encoding request header has previously been set for the resource, that value is returned in this header.", + "type": "string" + }, + "Content-Language": { + "description": "If the Content-Language request header has previously been set for the resource, that value is returned in this header.", + "type": "string" + }, + "Content-Length": { + "description": "The size of the resource in bytes.", + "type": "integer", + "format": "int64" + }, + "Content-Type": { + "description": "The content type specified for the resource. If no content type was specified, the default content type is application/octet-stream.", + "type": "string" + }, + "Content-MD5": { + "description": "An MD5 hash of the request content. This header is only returned for \"Flush\" operation. This header is returned so that the client can check for message content integrity. This header refers to the content of the request, not actual file content.", + "type": "string", + "format": "byte" + }, + "x-ms-properties": { + "x-ms-client-name": "Properties", + "description": "User-defined properties associated with the file or directory, in the format of a comma-separated list of name and value pairs \"n1=v1, n2=v2, ...\", where each value is a base64 encoded string. Note that the string may only contain ASCII characters in the ISO-8859-1 character set.", + "type": "string" + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation.", + "pattern": "^[{(]?[0-9a-f]{8}[-]?([0-9a-f]{4}[-]?){3}[0-9a-f]{12}[)}]?$", + "type": "string" + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "description": "The version of the REST protocol used to process the request.", + "type": "string" + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "The version of the REST protocol used to process the request." + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "$ref": "#/parameters/FileSystem" + }, + { + "$ref": "#/parameters/Path" + }, + { + "name": "action", + "description": "action", + "in": "query", + "required": true, + "type": "string", + "enum": ["setProperties"] + } + ] + }, + "/{filesystem}/{path}?action=flush": { + "patch": { + "tags": ["directory"], + "operationId": "Path_FlushData", + "description": "Set the owner, group, permissions, or access control list for a path.", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/Position" + }, + { + "$ref": "#/parameters/RetainUncommittedData" + }, + { + "$ref": "#/parameters/Close" + }, + { + "$ref": "#/parameters/ContentLength" + }, + { + "$ref": "#/parameters/ContentMD5" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/CacheControl" + }, + { + "$ref": "#/parameters/ContentType" + }, + { + "$ref": "#/parameters/ContentDisposition" + }, + { + "$ref": "#/parameters/ContentEncoding" + }, + { + "$ref": "#/parameters/ContentLanguage" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/EncryptionKey" + }, + { + "$ref": "#/parameters/EncryptionKeySha256" + }, + { + "$ref": "#/parameters/EncryptionAlgorithm" + }, + { + "$ref": "#/parameters/ProposedLeaseIdOptional" + }, + { + "$ref": "#/parameters/LeaseDuration" + }, + { + "$ref": "#/parameters/LeaseAction" + } + ], + "responses": { + "200": { + "description": "The data was flushed (written) to the file successfully.", + "headers": { + "Date": { + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated.", + "type": "string", + "format": "date-time-rfc1123" + }, + "ETag": { + "description": "An HTTP entity tag associated with the file or directory.", + "type": "string" + }, + "Last-Modified": { + "description": "The data and time the file or directory was last modified. Write operations on the file or directory update the last modified time.", + "format": "date-time-rfc1123", + "type": "string" + }, + "Content-Length": { + "description": "The size of the resource in bytes.", + "type": "integer", + "format": "int64" + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation.", + "pattern": "^[{(]?[0-9a-f]{8}[-]?([0-9a-f]{4}[-]?){3}[0-9a-f]{12}[)}]?$", + "type": "string" + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "description": "The version of the REST protocol used to process the request.", + "type": "string" + }, + "x-ms-request-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the contents of the request are successfully encrypted using the specified algorithm, and false otherwise." + }, + "x-ms-encryption-key-sha256": { + "x-ms-client-name": "EncryptionKeySha256", + "type": "string", + "description": "The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned when the blob was encrypted with a customer-provided key." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "The version of the REST protocol used to process the request." + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "$ref": "#/parameters/FileSystem" + }, + { + "$ref": "#/parameters/Path" + }, + { + "name": "action", + "description": "action", + "in": "query", + "required": true, + "type": "string", + "enum": ["flush"] + } + ] + }, + "/{filesystem}/{path}?action=append": { + "patch": { + "tags": ["directory"], + "operationId": "Path_AppendData", + "description": "Append data to the file.", + "parameters": [ + { + "$ref": "#/parameters/Position" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ContentLength" + }, + { + "$ref": "#/parameters/TransactionalContentMD5" + }, + { + "$ref": "#/parameters/ContentCrc64" + }, + { + "$ref": "#/parameters/LeaseIdOptional" + }, + { + "$ref": "#/parameters/Body" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/EncryptionKey" + }, + { + "$ref": "#/parameters/EncryptionKeySha256" + }, + { + "$ref": "#/parameters/EncryptionAlgorithm" + }, + { + "$ref": "#/parameters/ProposedLeaseIdOptional" + }, + { + "$ref": "#/parameters/LeaseDuration" + }, + { + "$ref": "#/parameters/LeaseAction" + }, + { + "$ref": "#/parameters/IfMatch" + }, + { + "$ref": "#/parameters/IfNoneMatch" + }, + { + "$ref": "#/parameters/IfModifiedSince" + }, + { + "$ref": "#/parameters/IfUnmodifiedSince" + }, + { + "name": "flush", + "in": "query", + "description": "Optional. This parameter allows the caller to flush during an append call. Default value is 'false' , if 'true' the data will be flushed with the append call. Note that when using flush=true, the following headers are not supported - 'x-ms-cache-control', 'x-ms-content-encoding', 'x-ms-content-type', 'x-ms-content-language', 'x-ms-content-md5', 'x-ms-content-disposition'. To set these headers during flush, please use action=flush", + "required": false, + "type": "boolean" + } + ], + "responses": { + "202": { + "description": "Append data to file control response.", + "headers": { + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "The version of the REST protocol used to process the request." + }, + "ETag": { + "description": "An HTTP entity tag associated with the file or directory.", + "type": "string" + }, + "Content-MD5": { + "type": "string", + "format": "byte", + "description": "If the blob has an MD5 hash and this operation is to read the full blob, this response header is returned so that the client can check for message content integrity." + }, + "x-ms-content-crc64": { + "type": "string", + "format": "byte", + "description": "This header is returned so that the client can check for message content integrity. The value of this header is computed by the Blob service; it is not necessarily the same value specified in the request headers." + }, + "x-ms-request-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the contents of the request are successfully encrypted using the specified algorithm, and false otherwise." + }, + "x-ms-encryption-key-sha256": { + "x-ms-client-name": "EncryptionKeySha256", + "type": "string", + "description": "The SHA-256 hash of the encryption key used to encrypt the blob. This header is only returned when the blob was encrypted with a customer-provided key." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "A server-generated UUID recorded in the analytics logs for troubleshooting and correlation." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "The version of the REST protocol used to process the request." + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "$ref": "#/parameters/FileSystem" + }, + { + "$ref": "#/parameters/Path" + }, + { + "name": "action", + "description": "action", + "in": "query", + "required": true, + "type": "string", + "enum": ["append"] + } + ] + }, + "/{filesystem}/{path}?comp=expiry": { + "put": { + "tags": ["blob"], + "operationId": "Path_SetExpiry", + "description": "Sets the time a blob will expire and be deleted.", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + }, + { + "$ref": "#/parameters/PathExpiryOptions" + }, + { + "$ref": "#/parameters/PathExpiryTime" + } + ], + "responses": { + "200": { + "description": "The blob expiry was set successfully.", + "headers": { + "ETag": { + "type": "string", + "description": "The ETag contains a value that you can use to perform operations conditionally. If the request version is 2011-08-18 or newer, the ETag value will be in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the container was last modified. Any operation that modifies the blob, including an update of the blob's metadata or properties, changes the last-modified time of the blob." + }, + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "$ref": "#/parameters/FileSystem" + }, + { + "$ref": "#/parameters/Path" + }, + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["expiry"] + } + ] + }, + "/{filesystem}/{path}?comp=undelete": { + "put": { + "tags": ["blob"], + "operationId": "Path_Undelete", + "description": "Undelete a path that was previously soft deleted", + "parameters": [ + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/UndeleteSource" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ClientRequestId" + } + ], + "responses": { + "200": { + "description": "The blob was undeleted successfully.", + "headers": { + "x-ms-client-request-id": { + "x-ms-client-name": "ClientRequestId", + "type": "string", + "description": "If a client request id header is sent in the request, this header will be present in the response with the same value." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-resource-type": { + "x-ms-client-name": "ResourceType", + "description": "The type of the resource. The value may be \"file\" or \"directory\". If not set, the value is \"file\".", + "type": "string" + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + { + "$ref": "#/parameters/FileSystem" + }, + { + "$ref": "#/parameters/Path" + }, + { + "name": "comp", + "description": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": ["undelete"] + } + ] + } + }, + "parameters": { + "Url": { + "name": "url", + "description": "The URL of the service account, container, or blob that is the target of the desired operation.", + "required": true, + "x-ms-parameter-location": "client", + "type": "string", + "in": "path", + "x-ms-skip-url-encoding": true + }, + "FileSystemResource": { + "name": "resource", + "in": "query", + "x-ms-parameter-location": "client", + "description": "The value must be \"filesystem\" for all filesystem operations.", + "required": true, + "type": "string", + "enum": ["filesystem"], + "x-ms-enum": { + "name": "FileSystemResourceType", + "modelAsString": false + } + }, + "ApiVersionParameter": { + "name": "x-ms-version", + "x-ms-parameter-location": "client", + "x-ms-client-name": "version", + "in": "header", + "required": false, + "type": "string", + "description": "Specifies the version of the operation to use for this request." + }, + "accountName": { + "description": "The Azure Storage account name.", + "in": "path", + "name": "accountName", + "required": true, + "type": "string", + "x-ms-skip-url-encoding": true, + "x-ms-parameter-location": "method" + }, + "dnsSuffix": { + "default": "dfs.core.windows.net", + "description": "The DNS suffix for the Azure Data Lake Storage endpoint.", + "in": "path", + "name": "dnsSuffix", + "required": true, + "type": "string", + "x-ms-skip-url-encoding": true, + "x-ms-parameter-location": "method" + }, + "ClientRequestId": { + "name": "x-ms-client-request-id", + "x-ms-client-name": "requestId", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "description": "Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled." + }, + "Timeout": { + "name": "timeout", + "in": "query", + "required": false, + "type": "integer", + "minimum": 0, + "x-ms-parameter-location": "method", + "description": "The timeout parameter is expressed in seconds. For more information, see Setting Timeouts for Blob Service Operations." + }, + "Range": { + "name": "x-ms-range", + "x-ms-client-name": "range", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "description": "The HTTP Range request header specifies one or more byte ranges of the resource to be retrieved." + }, + "GetRangeContentMD5": { + "name": "x-ms-range-get-content-md5", + "x-ms-client-name": "rangeGetContentMD5", + "in": "header", + "required": false, + "type": "boolean", + "x-ms-parameter-location": "method", + "description": "Optional. When this header is set to \"true\" and specified together with the Range header, the service returns the MD5 hash for the range, as long as the range is less than or equal to 4MB in size. If this header is specified without the Range header, the service returns status code 400 (Bad Request). If this header is set to true when the range exceeds 4 MB in size, the service returns status code 400 (Bad Request)." + }, + "GetRangeContentCRC64": { + "name": "x-ms-range-get-content-crc64", + "x-ms-client-name": "rangeGetContentCRC64", + "in": "header", + "required": false, + "type": "boolean", + "x-ms-parameter-location": "method", + "description": "When set to true and specified together with the Range, the service returns the CRC64 hash for the range, as long as the range is less than or equal to 4 MB in size." + }, + "DeleteSnapshots": { + "name": "x-ms-delete-snapshots", + "x-ms-client-name": "deleteSnapshots", + "description": "Required if the blob has associated snapshots. Specify one of the following two options: include: Delete the base blob and all of its snapshots. only: Delete only the blob's snapshots and not the blob itself", + "x-ms-parameter-location": "method", + "in": "header", + "required": false, + "type": "string", + "enum": ["include", "only"], + "x-ms-enum": { + "name": "DeleteSnapshotsOptionType", + "modelAsString": false + } + }, + "BlobDeleteType": { + "name": "deletetype", + "x-ms-client-name": "blobDeleteType", + "in": "query", + "required": false, + "type": "string", + "enum": ["Permanent"], + "x-ms-enum": { + "name": "BlobDeleteType", + "modelAsString": false + }, + "x-ms-parameter-location": "method", + "description": "Optional. Only possible value is 'permanent', which specifies to permanently delete a blob if blob soft delete is enabled." + }, + "IfMatch": { + "name": "If-Match", + "x-ms-client-name": "ifMatch", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "modified-access-conditions" + }, + "description": "Specify an ETag value to operate only on blobs with a matching value." + }, + "IfModifiedSince": { + "name": "If-Modified-Since", + "x-ms-client-name": "ifModifiedSince", + "in": "header", + "required": false, + "type": "string", + "format": "date-time-rfc1123", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "modified-access-conditions" + }, + "description": "Specify this header value to operate only on a blob if it has been modified since the specified date/time." + }, + "IfNoneMatch": { + "name": "If-None-Match", + "x-ms-client-name": "ifNoneMatch", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "modified-access-conditions" + }, + "description": "Specify an ETag value to operate only on blobs without a matching value." + }, + "IfUnmodifiedSince": { + "name": "If-Unmodified-Since", + "x-ms-client-name": "ifUnmodifiedSince", + "in": "header", + "required": false, + "type": "string", + "format": "date-time-rfc1123", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "modified-access-conditions" + }, + "description": "Specify this header value to operate only on a blob if it has not been modified since the specified date/time." + }, + "IfTags": { + "name": "x-ms-if-tags", + "x-ms-client-name": "ifTags", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "modified-access-conditions" + }, + "description": "Specify a SQL where clause on blob tags to operate only on blobs with a matching value." + }, + "Snapshot": { + "name": "snapshot", + "in": "query", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "description": "The snapshot parameter is an opaque DateTime value that, when present, specifies the blob snapshot to retrieve. For more information on working with blob snapshots, see Creating a Snapshot of a Blob." + }, + "VersionId": { + "name": "versionid", + "x-ms-client-name": "versionId", + "in": "query", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "description": "The version id parameter is an opaque DateTime value that, when present, specifies the version of the blob to operate on. It's for service version 2019-10-10 and newer." + }, + "RecursiveOptional": { + "name": "recursive", + "x-ms-parameter-location": "method", + "in": "query", + "description": "Required", + "required": false, + "type": "boolean" + }, + "RecursiveRequired": { + "name": "recursive", + "x-ms-parameter-location": "method", + "in": "query", + "description": "Required", + "required": true, + "type": "boolean" + }, + "Continuation": { + "name": "continuation", + "x-ms-parameter-location": "method", + "in": "query", + "description": "Optional. When deleting a directory, the number of paths that are deleted with each invocation is limited. If the number of paths to be deleted exceeds this limit, a continuation token is returned in this response header. When a continuation token is returned in the response, it must be specified in a subsequent invocation of the delete operation to continue deleting the directory.", + "required": false, + "type": "string" + }, + "PathSetAccessControlRecursiveMode": { + "name": "mode", + "in": "query", + "x-ms-parameter-location": "method", + "description": "Mode \"set\" sets POSIX access control rights on files and directories, \"modify\" modifies one or more POSIX access control rights that pre-exist on files and directories, \"remove\" removes one or more POSIX access control rights that were present earlier on files and directories", + "required": true, + "type": "string", + "enum": ["set", "modify", "remove"], + "x-ms-enum": { + "name": "PathSetAccessControlRecursiveMode", + "modelAsString": false + } + }, + "ForceFlag": { + "name": "forceFlag", + "x-ms-parameter-location": "method", + "in": "query", + "description": "Optional. Valid for \"SetAccessControlRecursive\" operation. If set to false, the operation will terminate quickly on encountering user errors (4XX). If true, the operation will ignore user errors and proceed with the operation on other sub-entities of the directory. Continuation token will only be returned when forceFlag is true in case of user errors. If not set the default value is false for this.", + "required": false, + "type": "boolean" + }, + "Directory": { + "name": "directory", + "x-ms-client-name": "Path", + "x-ms-parameter-location": "method", + "in": "query", + "description": "Optional. Filters results to paths within the specified directory. An error occurs if the directory does not exist.", + "required": false, + "type": "string" + }, + "LeaseIdOptional": { + "name": "x-ms-lease-id", + "x-ms-client-name": "leaseId", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "lease-access-conditions" + }, + "description": "If specified, the operation only succeeds if the resource's lease is active and matches this ID." + }, + "LeaseIdRequired": { + "name": "x-ms-lease-id", + "x-ms-client-name": "leaseId", + "in": "header", + "required": true, + "type": "string", + "x-ms-parameter-location": "method", + "description": "Specifies the current lease ID on the resource." + }, + "ProposedLeaseIdOptional": { + "name": "x-ms-proposed-lease-id", + "x-ms-client-name": "proposedLeaseId", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "description": "Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid Constructor (String) for a list of valid GUID string formats." + }, + "LeaseDuration": { + "name": "x-ms-lease-duration", + "in": "header", + "description": "The lease duration is required to acquire a lease, and specifies the duration of the lease in seconds. The lease duration must be between 15 and 60 seconds or -1 for infinite lease.", + "format": "int32", + "required": false, + "type": "integer", + "x-ms-parameter-location": "client" + }, + "LeaseAction": { + "name": "x-ms-lease-action", + "x-ms-client-name": "leaseAction", + "in": "header", + "required": false, + "type": "string", + "enum": [ + "acquire", + "release", + "renew", + "break", + "change", + "auto-renew", + "acquire-release" + ], + "x-ms-enum": { + "name": "LeaseAction", + "modelAsString": false + }, + "x-ms-parameter-location": "method", + "description": "Describes what lease action to take." + }, + "LeaseDurationMethod": { + "name": "x-ms-lease-duration", + "x-ms-client-name": "leaseDuration", + "in": "header", + "description": "The lease duration is required to acquire a lease, and specifies the duration of the lease in seconds. The lease duration must be between 15 and 60 seconds or -1 for infinite lease.", + "format": "int64", + "required": false, + "type": "integer", + "x-ms-parameter-location": "method" + }, + "Prefix": { + "name": "prefix", + "in": "query", + "description": "Filters results to filesystems within the specified prefix.", + "required": false, + "type": "string", + "x-ms-parameter-location": "method" + }, + "MaxResults": { + "name": "maxResults", + "in": "query", + "description": "An optional value that specifies the maximum number of items to return. If omitted or greater than 5,000, the response will include up to 5,000 items.", + "format": "int32", + "minimum": 1, + "required": false, + "type": "integer", + "x-ms-parameter-location": "method" + }, + "MaxResultsBlob": { + "name": "maxresults", + "in": "query", + "required": false, + "type": "integer", + "minimum": 1, + "x-ms-parameter-location": "method", + "description": "Specifies the maximum number of containers to return. If the request does not specify maxresults, or specifies a value greater than 5000, the server will return up to 5000 items. Note that if the listing operation crosses a partition boundary, then the service will return a continuation token for retrieving the remainder of the results. For this reason, it is possible that the service will return fewer results than specified by maxresults, or than the default of 5000." + }, + "Properties": { + "name": "x-ms-properties", + "x-ms-client-name": "properties", + "description": "Optional. User-defined properties to be stored with the filesystem, in the format of a comma-separated list of name and value pairs \"n1=v1, n2=v2, ...\", where each value is a base64 encoded string. Note that the string may only contain ASCII characters in the ISO-8859-1 character set. If the filesystem exists, any properties not included in the list will be removed. All properties are removed if the header is omitted. To merge new and existing properties, first get all existing properties and the current E-Tag, then make a conditional request with the E-Tag and include values for all properties.", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method" + }, + "SourceIfMatch": { + "name": "x-ms-source-if-match", + "x-ms-client-name": "sourceIfMatch", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "source-modified-access-conditions" + }, + "description": "Specify an ETag value to operate only on blobs with a matching value." + }, + "SourceIfModifiedSince": { + "name": "x-ms-source-if-modified-since", + "x-ms-client-name": "sourceIfModifiedSince", + "in": "header", + "required": false, + "type": "string", + "format": "date-time-rfc1123", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "source-modified-access-conditions" + }, + "description": "Specify this header value to operate only on a blob if it has been modified since the specified date/time." + }, + "SourceIfNoneMatch": { + "name": "x-ms-source-if-none-match", + "x-ms-client-name": "sourceIfNoneMatch", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "source-modified-access-conditions" + }, + "description": "Specify an ETag value to operate only on blobs without a matching value." + }, + "SourceIfUnmodifiedSince": { + "name": "x-ms-source-if-unmodified-since", + "x-ms-client-name": "sourceIfUnmodifiedSince", + "in": "header", + "required": false, + "type": "string", + "format": "date-time-rfc1123", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "source-modified-access-conditions" + }, + "description": "Specify this header value to operate only on a blob if it has not been modified since the specified date/time." + }, + "SourceLeaseId": { + "name": "x-ms-source-lease-id", + "x-ms-client-name": "sourceLeaseId", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "description": "A lease ID for the source path. If specified, the source path must have an active lease and the lease ID must match." + }, + "FileSystem": { + "name": "filesystem", + "x-ms-parameter-location": "client", + "x-ms-client-name": "fileSystem", + "in": "path", + "description": "The filesystem identifier.", + "pattern": "^[$a-z0-9](?!.*--)[-a-z0-9]{1,61}[a-z0-9]$", + "minLength": 3, + "maxLength": 63, + "required": true, + "type": "string" + }, + "Path": { + "name": "path", + "x-ms-parameter-location": "client", + "in": "path", + "description": "The file or directory path.", + "required": true, + "type": "string" + }, + "CacheControl": { + "name": "x-ms-cache-control", + "x-ms-client-name": "cacheControl", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "path-HTTP-headers" + }, + "description": "Optional. Sets the blob's cache control. If specified, this property is stored with the blob and returned with a read request." + }, + "ContentDisposition": { + "name": "x-ms-content-disposition", + "x-ms-client-name": "contentDisposition", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "path-HTTP-headers" + }, + "description": "Optional. Sets the blob's Content-Disposition header." + }, + "ContentEncoding": { + "name": "x-ms-content-encoding", + "x-ms-client-name": "contentEncoding", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "path-HTTP-headers" + }, + "description": "Optional. Sets the blob's content encoding. If specified, this property is stored with the blob and returned with a read request." + }, + "ContentLanguage": { + "name": "x-ms-content-language", + "x-ms-client-name": "contentLanguage", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "path-HTTP-headers" + }, + "description": "Optional. Set the blob's content language. If specified, this property is stored with the blob and returned with a read request." + }, + "ContentType": { + "name": "x-ms-content-type", + "x-ms-client-name": "contentType", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "path-HTTP-headers" + }, + "description": "Optional. Sets the blob's content type. If specified, this property is stored with the blob and returned with a read request." + }, + "TransactionalContentMD5": { + "name": "Content-MD5", + "x-ms-client-name": "transactionalContentHash", + "in": "header", + "required": false, + "type": "string", + "format": "byte", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "path-HTTP-headers" + }, + "description": "Specify the transactional md5 for the body, to be validated by the service." + }, + "ContentMD5": { + "name": "x-ms-content-md5", + "x-ms-client-name": "contentMD5", + "in": "header", + "required": false, + "type": "string", + "format": "byte", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "path-HTTP-headers" + }, + "description": "Specify the transactional md5 for the body, to be validated by the service." + }, + "ContentCrc64": { + "name": "x-ms-content-crc64", + "x-ms-client-name": "transactionalContentCrc64", + "in": "header", + "required": false, + "type": "string", + "format": "byte", + "x-ms-parameter-location": "method", + "description": "Specify the transactional crc64 for the body, to be validated by the service." + }, + "Umask": { + "name": "x-ms-umask", + "x-ms-client-name": "umask", + "description": "Optional and only valid if Hierarchical Namespace is enabled for the account. When creating a file or directory and the parent folder does not have a default ACL, the umask restricts the permissions of the file or directory to be created. The resulting permission is given by p bitwise and not u, where p is the permission and u is the umask. For example, if p is 0777 and u is 0057, then the resulting permission is 0720. The default permission is 0777 for a directory and 0666 for a file. The default umask is 0027. The umask must be specified in 4-digit octal notation (e.g. 0766).", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method" + }, + "Permissions": { + "name": "x-ms-permissions", + "x-ms-client-name": "permissions", + "description": "Optional and only valid if Hierarchical Namespace is enabled for the account. Sets POSIX access permissions for the file owner, the file owning group, and others. Each class may be granted read, write, or execute permission. The sticky bit is also supported. Both symbolic (rwxrw-rw-) and 4-digit octal notation (e.g. 0766) are supported.", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method" + }, + "RenameSource": { + "name": "x-ms-rename-source", + "x-ms-client-name": "renameSource", + "in": "header", + "description": "An optional file or directory to be renamed. The value must have the following format: \"/{filesystem}/{path}\". If \"x-ms-properties\" is specified, the properties will overwrite the existing properties; otherwise, the existing properties will be preserved. This value must be a URL percent-encoded string. Note that the string may only contain ASCII characters in the ISO-8859-1 character set.", + "required": false, + "type": "string", + "x-ms-parameter-location": "method" + }, + "Owner": { + "name": "x-ms-owner", + "x-ms-client-name": "owner", + "in": "header", + "required": false, + "type": "string", + "description": "Optional. The owner of the blob or directory.", + "x-ms-parameter-location": "method" + }, + "Group": { + "name": "x-ms-group", + "x-ms-client-name": "group", + "in": "header", + "required": false, + "type": "string", + "description": "Optional. The owning group of the blob or directory.", + "x-ms-parameter-location": "method" + }, + "Acl": { + "name": "x-ms-acl", + "description": "Sets POSIX access control rights on files and directories. The value is a comma-separated list of access control entries. Each access control entry (ACE) consists of a scope, a type, a user or group identifier, and permissions in the format \"[scope:][type]:[id]:[permissions]\".", + "x-ms-client-name": "acl", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method" + }, + "Body": { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "format": "file" + }, + "x-ms-parameter-location": "method", + "description": "Initial data" + }, + "Upn": { + "name": "upn", + "in": "query", + "description": "Optional. Valid only when Hierarchical Namespace is enabled for the account. If \"true\", the user identity values returned in the x-ms-owner, x-ms-group, and x-ms-acl response headers will be transformed from Azure Active Directory Object IDs to User Principal Names. If \"false\", the values will be returned as Azure Active Directory Object IDs. The default value is false. Note that group and application Object IDs are not translated because they do not have unique friendly names.", + "required": false, + "type": "boolean", + "x-ms-parameter-location": "method" + }, + "Position": { + "name": "position", + "in": "query", + "description": "This parameter allows the caller to upload data in parallel and control the order in which it is appended to the file. It is required when uploading data to be appended to the file and when flushing previously uploaded data to the file. The value must be the position where the data is to be appended. Uploaded data is not immediately flushed, or written, to the file. To flush, the previously uploaded data must be contiguous, the position parameter must be specified and equal to the length of the file after all data has been written, and there must not be a request entity body included with the request.", + "format": "int64", + "required": false, + "type": "integer", + "x-ms-parameter-location": "method" + }, + "RetainUncommittedData": { + "name": "retainUncommittedData", + "in": "query", + "description": "Valid only for flush operations. If \"true\", uncommitted data is retained after the flush operation completes; otherwise, the uncommitted data is deleted after the flush operation. The default is false. Data at offsets less than the specified position are written to the file when flush succeeds, but this optional parameter allows data after the flush position to be retained for a future flush operation.", + "required": false, + "type": "boolean", + "x-ms-parameter-location": "method" + }, + "Close": { + "name": "close", + "in": "query", + "description": "Azure Storage Events allow applications to receive notifications when files change. When Azure Storage Events are enabled, a file changed event is raised. This event has a property indicating whether this is the final change to distinguish the difference between an intermediate flush to a file stream and the final close of a file stream. The close query parameter is valid only when the action is \"flush\" and change notifications are enabled. If the value of close is \"true\" and the flush operation completes successfully, the service raises a file change notification with a property indicating that this is the final update (the file stream has been closed). If \"false\" a change notification is raised indicating the file has changed. The default is false. This query parameter is set to true by the Hadoop ABFS driver to indicate that the file stream has been closed.\"", + "required": false, + "type": "boolean", + "x-ms-parameter-location": "method" + }, + "ContentLength": { + "name": "Content-Length", + "in": "header", + "description": "Required for \"Append Data\" and \"Flush Data\". Must be 0 for \"Flush Data\". Must be the length of the request content in bytes for \"Append Data\".", + "minimum": 0, + "required": false, + "type": "integer", + "format": "int64", + "x-ms-parameter-location": "method" + }, + "PathExpiryOptions": { + "name": "x-ms-expiry-option", + "x-ms-client-name": "ExpiryOptions", + "in": "header", + "required": true, + "type": "string", + "enum": [ + "NeverExpire", + "RelativeToCreation", + "RelativeToNow", + "Absolute" + ], + "x-ms-enum": { + "name": "PathExpiryOptions", + "modelAsString": true + }, + "x-ms-parameter-location": "method", + "description": "Required. Indicates mode of the expiry time" + }, + "PathExpiryOptionsOptional": { + "name": "x-ms-expiry-option", + "x-ms-client-name": "ExpiryOptions", + "in": "header", + "required": false, + "type": "string", + "enum": [ + "NeverExpire", + "RelativeToCreation", + "RelativeToNow", + "Absolute" + ], + "x-ms-enum": { + "name": "PathExpiryOptions", + "modelAsString": true + }, + "x-ms-parameter-location": "method", + "description": "Required. Indicates mode of the expiry time" + }, + "PathExpiryTime": { + "name": "x-ms-expiry-time", + "x-ms-client-name": "ExpiresOn", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "description": "The time to set the blob to expiry" + }, + "Metadata": { + "name": "x-ms-meta", + "x-ms-client-name": "metadata", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "description": "Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or file to the destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more information.", + "x-ms-header-collection-prefix": "x-ms-meta-" + }, + "UndeleteSource": { + "name": "x-ms-undelete-source", + "x-ms-client-name": "UndeleteSource", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "description": "Only for hierarchical namespace enabled accounts. Optional. The path of the soft deleted blob to undelete." + }, + "Marker": { + "name": "marker", + "in": "query", + "required": false, + "type": "string", + "description": "A string value that identifies the portion of the list of containers to be returned with the next listing operation. The operation returns the NextMarker value within the response body if the listing operation did not return all containers remaining to be listed with the current page. The NextMarker value can be used as the value for the marker parameter in a subsequent call to request the next page of list items. The marker value is opaque to the client.", + "x-ms-parameter-location": "method" + }, + "ListBlobsInclude": { + "name": "include", + "in": "query", + "required": false, + "type": "array", + "collectionFormat": "csv", + "items": { + "type": "string", + "enum": [ + "", + "copy", + "deleted", + "metadata", + "snapshots", + "uncommittedblobs", + "versions", + "tags", + "immutabilitypolicy", + "legalhold", + "deletedwithversions", + "permissions" + ], + "x-ms-enum": { + "name": "ListBlobsIncludeItem", + "modelAsString": false + } + }, + "x-ms-parameter-location": "method", + "description": "Include this parameter to specify one or more datasets to include in the response." + }, + "ListBlobsShowOnly": { + "name": "showonly", + "in": "query", + "required": false, + "type": "string", + "enum": ["deleted"], + "x-ms-enum": { + "name": "ListBlobsShowOnly", + "modelAsString": false + }, + "x-ms-parameter-location": "method", + "description": "Include this parameter to specify one or more datasets to include in the response." + }, + "Delimiter": { + "name": "delimiter", + "description": "When the request includes this parameter, the operation returns a BlobPrefix element in the response body that acts as a placeholder for all blobs whose names begin with the same substring up to the appearance of the delimiter character. The delimiter may be a single character or a string.", + "type": "string", + "x-ms-parameter-location": "method", + "in": "query", + "required": true + }, + "EncryptionKey": { + "name": "x-ms-encryption-key", + "x-ms-client-name": "encryptionKey", + "type": "string", + "in": "header", + "required": false, + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "cpk-info" + }, + "description": "Optional. Specifies the encryption key to use to encrypt the data provided in the request. If not specified, encryption is performed with the root account encryption key. For more information, see Encryption at Rest for Azure Storage Services." + }, + "EncryptionKeySha256": { + "name": "x-ms-encryption-key-sha256", + "x-ms-client-name": "encryptionKeySha256", + "type": "string", + "in": "header", + "required": false, + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "cpk-info" + }, + "description": "The SHA-256 hash of the provided encryption key. Must be provided if the x-ms-encryption-key header is provided." + }, + "EncryptionAlgorithm": { + "name": "x-ms-encryption-algorithm", + "x-ms-client-name": "encryptionAlgorithm", + "type": "string", + "in": "header", + "required": false, + "enum": ["AES256"], + "x-ms-enum": { + "name": "EncryptionAlgorithmType", + "modelAsString": false + }, + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "name": "cpk-info" + }, + "description": "The algorithm used to produce the encryption key hash. Currently, the only accepted value is \"AES256\". Must be provided if the x-ms-encryption-key header is provided." + } + }, + "definitions": { + "AclFailedEntry": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "errorMessage": { + "type": "string" + } + } + }, + "SetAccessControlRecursiveResponse": { + "type": "object", + "properties": { + "directoriesSuccessful": { + "type": "integer", + "format": "int32" + }, + "filesSuccessful": { + "type": "integer", + "format": "int32" + }, + "failureCount": { + "type": "integer", + "format": "int32" + }, + "failedEntries": { + "type": "array", + "items": { + "$ref": "#/definitions/AclFailedEntry" + } + } + } + }, + "Path": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "isDirectory": { + "default": false, + "type": "boolean" + }, + "lastModified": { + "type": "string", + "format": "date-time-rfc1123" + }, + "etag": { + "type": "string" + }, + "contentLength": { + "type": "integer", + "format": "int64" + }, + "owner": { + "type": "string" + }, + "group": { + "type": "string" + }, + "permissions": { + "type": "string" + }, + "EncryptionScope": { + "type": "string", + "description": "The name of the encryption scope under which the blob is encrypted." + } + } + }, + "PathList": { + "type": "object", + "xml": { + "name": "paths" + }, + "properties": { + "paths": { + "xml": { + "name": "paths" + }, + "type": "array", + "items": { + "$ref": "#/definitions/Path" + } + } + } + }, + "FileSystem": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "lastModified": { + "type": "string" + }, + "eTag": { + "type": "string" + } + } + }, + "ListBlobsFlatSegmentResponse": { + "xml": { + "name": "EnumerationResults" + }, + "description": "An enumeration of blobs", + "type": "object", + "required": ["ServiceEndpoint", "ContainerName", "Segment"], + "properties": { + "ServiceEndpoint": { + "type": "string", + "xml": { + "attribute": true + } + }, + "ContainerName": { + "type": "string", + "xml": { + "attribute": true + } + }, + "Prefix": { + "type": "string" + }, + "Marker": { + "type": "string" + }, + "MaxResults": { + "type": "integer" + }, + "Segment": { + "$ref": "#/definitions/BlobFlatListSegment" + }, + "NextMarker": { + "type": "string" + } + } + }, + "ListBlobsHierarchySegmentResponse": { + "xml": { + "name": "EnumerationResults" + }, + "description": "An enumeration of blobs", + "type": "object", + "required": ["ServiceEndpoint", "ContainerName", "Segment"], + "properties": { + "ServiceEndpoint": { + "type": "string", + "xml": { + "attribute": true + } + }, + "ContainerName": { + "type": "string", + "xml": { + "attribute": true + } + }, + "Prefix": { + "type": "string" + }, + "Marker": { + "type": "string" + }, + "MaxResults": { + "type": "integer" + }, + "Delimiter": { + "type": "string" + }, + "Segment": { + "$ref": "#/definitions/BlobHierarchyListSegment" + }, + "NextMarker": { + "type": "string" + } + } + }, + "BlobFlatListSegment": { + "xml": { + "name": "Blobs" + }, + "required": ["BlobItems"], + "type": "object", + "properties": { + "BlobItems": { + "type": "array", + "items": { + "$ref": "#/definitions/BlobItemInternal" + } + } + } + }, + "BlobHierarchyListSegment": { + "xml": { + "name": "Blobs" + }, + "type": "object", + "required": ["BlobItems"], + "properties": { + "BlobPrefixes": { + "type": "array", + "items": { + "$ref": "#/definitions/BlobPrefix" + } + }, + "BlobItems": { + "type": "array", + "items": { + "$ref": "#/definitions/BlobItemInternal" + } + } + } + }, + "BlobPrefix": { + "type": "object", + "required": ["Name"], + "properties": { + "Name": { + "type": "string" + } + } + }, + "BlobItemInternal": { + "xml": { + "name": "Blob" + }, + "description": "An Azure Storage blob", + "type": "object", + "required": ["Name", "Properties"], + "properties": { + "Name": { + "type": "string" + }, + "Deleted": { + "type": "boolean" + }, + "Snapshot": { + "type": "string" + }, + "VersionId": { + "type": "string" + }, + "IsCurrentVersion": { + "type": "boolean" + }, + "Properties": { + "$ref": "#/definitions/BlobPropertiesInternal" + }, + "DeletionId": { + "type": "string" + } + } + }, + "BlobPropertiesInternal": { + "xml": { + "name": "Properties" + }, + "description": "Properties of a blob", + "type": "object", + "required": ["Etag", "Last-Modified"], + "properties": { + "Creation-Time": { + "type": "string", + "format": "date-time-rfc1123" + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123" + }, + "Etag": { + "type": "string" + }, + "Content-Length": { + "type": "integer", + "format": "int64", + "description": "Size in bytes" + }, + "Content-Type": { + "type": "string" + }, + "Content-Encoding": { + "type": "string" + }, + "Content-Language": { + "type": "string" + }, + "Content-MD5": { + "type": "string", + "format": "byte" + }, + "Content-Disposition": { + "type": "string" + }, + "Cache-Control": { + "type": "string" + }, + "x-ms-blob-sequence-number": { + "x-ms-client-name": "blobSequenceNumber", + "type": "integer", + "format": "int64" + }, + "CopyId": { + "type": "string" + }, + "CopySource": { + "type": "string" + }, + "CopyProgress": { + "type": "string" + }, + "CopyCompletionTime": { + "type": "string", + "format": "date-time-rfc1123" + }, + "CopyStatusDescription": { + "type": "string" + }, + "ServerEncrypted": { + "type": "boolean" + }, + "IncrementalCopy": { + "type": "boolean" + }, + "DestinationSnapshot": { + "type": "string" + }, + "DeletedTime": { + "type": "string", + "format": "date-time-rfc1123" + }, + "RemainingRetentionDays": { + "type": "integer" + }, + "AccessTierInferred": { + "type": "boolean" + }, + "CustomerProvidedKeySha256": { + "type": "string" + }, + "EncryptionScope": { + "type": "string", + "description": "The name of the encryption scope under which the blob is encrypted." + }, + "AccessTierChangeTime": { + "type": "string", + "format": "date-time-rfc1123" + }, + "TagCount": { + "type": "integer" + }, + "Expiry-Time": { + "x-ms-client-name": "ExpiresOn", + "type": "string", + "format": "date-time-rfc1123" + }, + "Sealed": { + "x-ms-client-name": "IsSealed", + "type": "boolean" + }, + "LastAccessTime": { + "x-ms-client-name": "LastAccessedOn", + "type": "string", + "format": "date-time-rfc1123" + }, + "DeleteTime": { + "type": "string", + "format": "date-time-rfc1123" + }, + "properties": { + "type": "string" + } + } + }, + "FileSystemList": { + "type": "object", + "properties": { + "filesystems": { + "type": "array", + "items": { + "$ref": "#/definitions/FileSystem" + } + } + } + }, + "StorageError": { + "type": "object", + "properties": { + "Message": { + "description": "The service error message.", + "type": "string" + }, + "error": { + "type": "object", + "description": "The service error response object.", + "properties": { + "Code": { + "description": "The service error code.", + "type": "string" + }, + "Message": { + "description": "The service error message.", + "type": "string" + } + } + } + } + } + } +} diff --git a/swagger/dfs.md b/swagger/dfs.md new file mode 100644 index 000000000..9bd2e122e --- /dev/null +++ b/swagger/dfs.md @@ -0,0 +1,46 @@ +# Azurite Server Blob + +> see https://aka.ms/autorest + +```yaml +package-name: azurite-server-blob +title: AzuriteServerBlob +package-version: 1.0.0 +description: Azurite Server for Blob +enable-xml: true +generate-metadata: false +license-header: MICROSOFT_MIT_NO_VERSION +output-folder: ../src/dfs/generated +input-file: + - data-lake-storage.json-2021-04-10.json + - blob-storage-2021-10-04-data-lake.json +model-date-time-as-string: true +optional-response-headers: true +enum-types: true +``` + +## Changes Made to Client Swagger + +1. Added metadata to all path operations +2. changed contentMd5 to bytes in Path_Read in both responses 200, 206 and in Path_GetProperties +3. added metadata to response of getproperties +4. added LeaseAction, LeaseDuration and proposedLeaseId to Path_Flush, Path_AppendData +5. added LeaseState, LeaseStatus to blob properties +6. added IfMacth, IfNoneMatch, IfModifiedSince, IfUnmodifiedSince, Path_AppendData +7. added XmlName("paths") to pathlist +8. added "format": "date-time-rfc1123" to lastModified +9. merge Blob_GetProperties and Path_GetProperties into Path_GetProperties and remove Blob_GetProperties +10. merge Blob_Delete and Path_Delete into Path_Delete and remove Blob_Delete +11. merge Blob_Download and Path_Read into Path_Read and remove Blob_Download +12. move container listBlobsFalt to dataLake swagger and rename it to filesystem listblobsFlat +13. move container listBlobsHierarchy & file system listBlobsHierarchy and remove container listBlobsHierarchy +14. add auto-renew, acquire-release to values permitted in lease action +15. eTag renamed to etag in Path model (required for hadoop) +16. add flush option to Path_AppendData as per spec +17. added Path_SetProperties from Path_Update spec +18. added expiresOn to Path in listPaths spec + +## Changes in Code: + +1. isxml set to false in listPaths (required for hadoop) +2. add req.getHeader("X-HTTP-Method-Override") to dispatch.middleware.ts (required for hadoop) diff --git a/tests/BlobTestServerFactory.ts b/tests/BlobTestServerFactory.ts index c37c19848..b62decd56 100644 --- a/tests/BlobTestServerFactory.ts +++ b/tests/BlobTestServerFactory.ts @@ -4,18 +4,23 @@ import SqlBlobConfiguration from "../src/blob/SqlBlobConfiguration"; import SqlBlobServer from "../src/blob/SqlBlobServer"; import { StoreDestinationArray } from "../src/common/persistence/IExtentStore"; import { DEFAULT_SQL_OPTIONS } from "../src/common/utils/constants"; +import DataLakeServer from "../src/dfs/DataLakeServer"; +import SqlDataLakeServer from "../src/dfs/SqlDataLakeServer"; export default class BlobTestServerFactory { + constructor(private readonly isDataLake: boolean = false) {} + public createServer( loose: boolean = false, skipApiVersionCheck: boolean = false, https: boolean = false, - oauth?: string - ): BlobServer | SqlBlobServer { + oauth?: string, + ): BlobServer | SqlBlobServer | DataLakeServer | SqlDataLakeServer { + const isDataLake: boolean = process.env.IS_DATALAKE == "true"|| this.isDataLake; const databaseConnectionString = process.env.AZURITE_TEST_DB; const isSQL = databaseConnectionString !== undefined; - const port = 11000; + const port = isDataLake ? 11003 : 11000; const host = "127.0.0.1"; const persistenceArray: StoreDestinationArray = [ { @@ -30,7 +35,7 @@ export default class BlobTestServerFactory { if (isSQL) { const config = new SqlBlobConfiguration( host, - port, + port + 100, databaseConnectionString!, DEFAULT_SQL_OPTIONS, persistenceArray, @@ -43,10 +48,12 @@ export default class BlobTestServerFactory { cert, key, undefined, - oauth + oauth, + false, + true ); - return new SqlBlobServer(config); + return isDataLake ? new SqlDataLakeServer(config) : new SqlBlobServer(config); } else { const lokiMetadataDBPath = "__test_db_blob__.json"; const lokiExtentDBPath = "__test_db_blob_extent__.json"; @@ -67,7 +74,7 @@ export default class BlobTestServerFactory { undefined, oauth ); - return new BlobServer(config); + return isDataLake ? new DataLakeServer(config) : new BlobServer(config); } } } diff --git a/tests/dfs/apis/aborter.test.ts b/tests/dfs/apis/aborter.test.ts new file mode 100644 index 000000000..253f0fce2 --- /dev/null +++ b/tests/dfs/apis/aborter.test.ts @@ -0,0 +1,116 @@ +// Copyright (c) Microsoft Corporation. +import assert from "assert"; +import { Context } from "mocha"; + +// Licensed under the MIT license. +import { AbortController, AbortSignal } from "@azure/abort-controller"; +import { + DataLakeFileSystemClient, + DataLakeServiceClient, + StorageSharedKeyCredential +} from "@azure/storage-file-datalake"; + +import { + EMULATOR_ACCOUNT_KEY, + EMULATOR_ACCOUNT_NAME, + getUniqueName +} from "../../testutils"; +import BlobTestServerFactory from "../../BlobTestServerFactory"; + +describe("Aborter", () => { + const factory = new BlobTestServerFactory(true); + const server = factory.createServer(); + + const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`; + const serviceClient = new DataLakeServiceClient( + baseURL, + new StorageSharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + + let fileSystemName: string; + let fileSystemClient: DataLakeFileSystemClient; + + before(async () => { + await server.start(); + }); + + after(async () => { + await server.close(); + await server.clean(); + }); + + beforeEach(async function (this: Context) { + checkIfShouldSkip(this); + fileSystemName = getUniqueName("filesystem"); + fileSystemClient = serviceClient.getFileSystemClient(fileSystemName); + }); + + afterEach(async function () { + await fileSystemClient.deleteIfExists(); + }); + + it("Should abort after aborter timeout @loki @sql", async () => { + try { + await fileSystemClient.create({ + abortSignal: AbortController.timeout(1) + }); + assert.fail(); + } catch (err: any) { + assert.equal(err.name, "AbortError"); + } + }); + + it("Should not abort after calling abort() @loki @sql", async () => { + await fileSystemClient.create({ abortSignal: AbortSignal.none }); + }); + + it("Should abort when calling abort() before request finishes @loki @sql", async () => { + const aborter = new AbortController(); + const response = fileSystemClient.create({ abortSignal: aborter.signal }); + aborter.abort(); + try { + await response; + assert.fail(); + } catch (err: any) { + assert.equal(err.name, "AbortError"); + } + }); + + it("Should not abort when calling abort() after request finishes @loki @sql", async () => { + const aborter = new AbortController(); + await fileSystemClient.create({ abortSignal: aborter.signal }); + aborter.abort(); + }); + + it("Should abort after father aborter calls abort() @loki @sql", async () => { + try { + const aborter = new AbortController(); + const childAborter = new AbortController( + aborter.signal, + AbortController.timeout(10 * 60 * 1000) + ); + const response = fileSystemClient.create({ + abortSignal: childAborter.signal + }); + aborter.abort(); + await response; + assert.fail(); + } catch (err: any) { + assert.equal(err.name, "AbortError"); + } + }); +}); + +function checkIfShouldSkip(context: Context) { + if ( + context.currentTest!.title.indexOf("ExpiryTime") > -1 || + context.test!.parent!.title.indexOf("soft delete") > -1 + ) { + context.skip(); + } +} diff --git a/tests/dfs/apis/file.test.ts b/tests/dfs/apis/file.test.ts new file mode 100644 index 000000000..99d4586af --- /dev/null +++ b/tests/dfs/apis/file.test.ts @@ -0,0 +1,1056 @@ +import { isNode } from "@azure/ms-rest-js"; +import { BlobServiceClient } from "@azure/storage-blob"; +import { + DataLakeServiceClient, + FileSystemListPathsResponse, + newPipeline, + StorageSharedKeyCredential +} from "@azure/storage-file-datalake"; + +import { configLogger } from "../../../src/common/Logger"; +import { BlobHTTPHeaders } from "../../../src/dfs/generated/artifacts/models"; +import { + bodyToString, + EMULATOR_ACCOUNT_KEY, + EMULATOR_ACCOUNT_NAME, + getUniqueName, + sleep, + upload +} from "../../testutils"; + +import assert = require("assert"); +import BlobTestServerFactory from "../../BlobTestServerFactory"; + +// Set true to enable debug log +configLogger(false); + +describe("fileAPIs", () => { + const factory = new BlobTestServerFactory(true); + const server = factory.createServer(); + + const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`; + const serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ) + ); + + const blobServiceClient = new BlobServiceClient( + baseURL, + newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ) + ); + + let fileSytemName: string = getUniqueName("filesystem"); + let fileSystemClient = serviceClient.getFileSystemClient(fileSytemName); + let fileName: string = getUniqueName("file"); + let fileClient = fileSystemClient.getFileClient(fileName); + let fileLeaseClient = fileClient.getDataLakeLeaseClient(); + + let containerClient = blobServiceClient.getContainerClient(fileSytemName); + let blobClient = containerClient.getBlobClient(fileName); + blobClient.accountName; + + const content = "Hello World"; + + before(async () => { + await server.start(); + }); + + after(async () => { + await server.close(); + await server.clean(); + }); + + beforeEach(async () => { + fileSytemName = getUniqueName("filesystem"); + fileSystemClient = serviceClient.getFileSystemClient(fileSytemName); + await fileSystemClient.create(); + fileName = getUniqueName("file"); + fileClient = fileSystemClient.getFileClient(fileName); + fileLeaseClient = fileClient.getDataLakeLeaseClient(); + await upload(fileClient, content); + containerClient = blobServiceClient.getContainerClient(fileSytemName); + blobClient = containerClient.getBlobClient(fileName); + }); + + afterEach(async () => { + await fileSystemClient.delete(); + }); + + it("download with with default parameters @loki @sql", async () => { + const result = await fileClient.read(); + assert.deepStrictEqual(await bodyToString(result, content.length), content); + assert.equal(result.contentRange, undefined); + assert.ok(result.requestId); + }); + + it("download should work with conditional headers @loki @sql", async () => { + const properties = await fileClient.getProperties(); + const result = await fileClient.read(0, undefined, { + conditions: { + ifMatch: properties.etag, + ifNoneMatch: "invalidetag", + ifModifiedSince: new Date("2018/01/01"), + ifUnmodifiedSince: new Date("2188/01/01") + } + }); + assert.deepStrictEqual(await bodyToString(result, content.length), content); + assert.equal(result.contentRange, undefined); + assert.ok(result.requestId); + }); + + it("download should work with ifMatch value * @loki @sql", async () => { + const result = await fileClient.read(0, undefined, { + conditions: { + ifMatch: "*,abc", + ifNoneMatch: "invalidetag", + ifModifiedSince: new Date("2018/01/01"), + ifUnmodifiedSince: new Date("2188/01/01") + } + }); + assert.deepStrictEqual(await bodyToString(result, content.length), content); + assert.equal(result.contentRange, undefined); + assert.ok(result.requestId); + }); + + it("download should not work with invalid conditional header ifMatch @loki @sql", async () => { + const properties = await fileClient.getProperties(); + try { + await fileClient.read(0, undefined, { + conditions: { + ifMatch: properties.etag + "invalid" + } + }); + } catch (error) { + assert.deepStrictEqual(error.statusCode, 412); + return; + } + assert.fail(); + }); + + it("download should not work with conditional header ifNoneMatch @loki @sql", async () => { + const properties = await fileClient.getProperties(); + try { + await fileClient.read(0, undefined, { + conditions: { + ifNoneMatch: properties.etag + } + }); + } catch (error) { + assert.deepStrictEqual(error.statusCode, 304); + return; + } + assert.fail(); + }); + + it("download should not work with conditional header ifNoneMatch * @loki @sql", async () => { + try { + await fileClient.read(0, undefined, { + conditions: { + ifNoneMatch: "*" + } + }); + } catch (error) { + assert.deepStrictEqual(error.statusCode, 400); + return; + } + assert.fail(); + }); + + it("download should not work with conditional header ifModifiedSince @loki @sql", async () => { + try { + await fileClient.read(0, undefined, { + conditions: { + ifModifiedSince: new Date("2120/01/01") + } + }); + } catch (error) { + assert.deepStrictEqual(error.statusCode, 304); + return; + } + assert.fail(); + }); + + it("download should not work with conditional header ifUnmodifiedSince @loki @sql", async () => { + try { + await fileClient.read(0, undefined, { + conditions: { + ifUnmodifiedSince: new Date("2018/01/01") + } + }); + } catch (error) { + assert.deepStrictEqual(error.statusCode, 412); + return; + } + assert.fail(); + }); + + it("download all parameters set @loki @sql", async () => { + const result = await fileClient.read(0, 1, { + rangeGetContentMD5: true + }); + assert.deepStrictEqual(await bodyToString(result, 1), content[0]); + assert.equal(result.contentRange, `bytes 0-0/${content.length}`); + assert.ok(result.requestId); + }); + + it("download entire with range @loki @sql", async () => { + const result = await fileClient.read(0, content.length); + assert.deepStrictEqual(await bodyToString(result, content.length), content); + assert.equal( + result.contentRange, + `bytes 0-${content.length - 1}/${content.length}` + ); + assert.ok(result.requestId); + }); + + it("download out of range @loki @sql", async () => { + try { + await fileClient.read(content.length + 1, content.length + 10); + } catch (error) { + assert.deepStrictEqual(error.statusCode, 416); + return; + } + assert.fail(); + }); + + it("get properties response should not set content-type @loki @sql", async () => { + const fileURL404 = fileSystemClient.getFileClient("UN_EXIST_file_"); + try { + await fileURL404.getProperties(); + } catch (err) { + assert.ok(!err.response.headers.get("content-type")); + } + + try { + await fileURL404.read(0, 0); + } catch (err) { + assert.notEqual(err.response.headers.get("content-type"), undefined); + } + }); + + it("delete @loki @sql", async () => { + const result = await fileClient.delete(); + assert.ok(result.requestId); + }); + + it("delete should work for valid ifMatch @loki @sql", async () => { + const properties = await fileClient.getProperties(); + + const result = await fileClient.delete(false, { + conditions: { + ifMatch: properties.etag + } + }); + assert.ok(result.requestId); + }); + + it("delete should work for * ifMatch @loki @sql", async () => { + const result = await fileClient.delete(false, { + conditions: { + ifMatch: "*" + } + }); + assert.ok(result.requestId); + }); + + it("delete should not work for invalid ifMatch @loki @sql", async () => { + try { + await fileClient.delete(false, { + conditions: { + ifMatch: "invalid" + } + }); + } catch (error) { + assert.deepStrictEqual(error.statusCode, 412); + return; + } + assert.fail(); + }); + + it("delete should work for valid ifNoneMatch @loki @sql", async () => { + const result = await fileClient.delete(false, { + conditions: { + ifNoneMatch: "unmatchetag" + } + }); + assert.ok(result.requestId); + }); + + it("delete should not work for invalid ifNoneMatch @loki @sql", async () => { + const properties = await fileClient.getProperties(); + + try { + await fileClient.delete(false, { + conditions: { + ifNoneMatch: properties.etag + } + }); + } catch (error) { + assert.deepStrictEqual(error.statusCode, 412); + return; + } + assert.fail(); + }); + + it("delete should work for ifNoneMatch * @loki @sql", async () => { + await fileClient.delete(false, { + conditions: { + ifNoneMatch: "*" + } + }); + }); + + it("delete should work for valid ifModifiedSince * @loki @sql", async () => { + await fileClient.delete(false, { + conditions: { + ifModifiedSince: new Date("2018/01/01") + } + }); + }); + + it("delete should not work for invalid ifModifiedSince @loki @sql", async () => { + try { + await fileClient.delete(false, { + conditions: { + ifModifiedSince: new Date("2118/01/01") + } + }); + } catch (error) { + assert.deepStrictEqual(error.statusCode, 412); + return; + } + assert.fail(); + }); + + it("delete should work for valid ifUnmodifiedSince * @loki @sql", async () => { + await fileClient.delete(false, { + conditions: { + ifUnmodifiedSince: new Date("2118/01/01") + } + }); + }); + + it("delete should not work for invalid ifUnmodifiedSince @loki @sql", async () => { + try { + await fileClient.delete(false, { + conditions: { + ifUnmodifiedSince: new Date("2018/01/01") + } + }); + } catch (error) { + assert.deepStrictEqual(error.statusCode, 412); + return; + } + assert.fail(); + }); + + it("should create a snapshot from a file @loki @sql", async () => { + const result = await blobClient.createSnapshot(); + assert.ok(result.snapshot); + assert.ok(result.requestId); + }); + + it("should create a snapshot with metadata from a file @loki @sql", async () => { + const metadata = { + meta1: "val1", + meta3: "val3" + }; + const result = await blobClient.createSnapshot({ metadata }); + assert.ok(result.snapshot); + assert.ok(result.requestId); + const result2 = await blobClient + .withSnapshot(result.snapshot!) + .getProperties(); + assert.deepStrictEqual(result2.metadata, metadata); + }); + + it("should not delete base file without include snapshot header @loki @sql", async () => { + const result = await blobClient.createSnapshot(); + assert.ok(result.snapshot); + assert.ok(result.requestId); + const fileSnapshotURL = blobClient.withSnapshot(result.snapshot!); + await fileSnapshotURL.getProperties(); + + let err; + try { + await fileClient.delete(false, {}); + } catch (error) { + err = error; + } + + assert.deepStrictEqual(err.statusCode, 409); + }); + + it("should delete snapshot @loki @sql", async () => { + const result = await blobClient.createSnapshot(); + assert.ok(result.snapshot); + assert.ok(result.requestId); + const fileSnapshotURL = blobClient.withSnapshot(result.snapshot!); + await fileSnapshotURL.getProperties(); + await fileSnapshotURL.delete(); + await fileClient.delete(); + const result2 = (await fileSystemClient.listPaths().byPage().next()) + .value as FileSystemListPathsResponse; + // Verify that the snapshot is deleted + assert.equal(result2.pathItems!.length, 0); + assert.ok(result2.requestId); + }); + + it("should setMetadata with new metadata set @loki @sql", async () => { + const metadata = { + a: "a", + b: "b" + }; + const result_setmeta = await fileClient.setMetadata(metadata); + assert.equal( + result_setmeta._response.request.headers.get("x-ms-client-request-id"), + result_setmeta.clientRequestId + ); + const result = await fileClient.getProperties(); + assert.deepStrictEqual(result.metadata, metadata); + assert.ok(result.requestId); + }); + + it("acquireLease_available_proposedLeaseId_fixed @loki @sql", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = 30; + fileLeaseClient = fileClient.getDataLakeLeaseClient(guid); + const result_acquire = await fileLeaseClient.acquireLease(duration); + assert.equal( + result_acquire._response.request.headers.get("x-ms-client-request-id"), + result_acquire._response.request.requestId + ); + + const result = await fileClient.getProperties(); + assert.equal(result.leaseDuration, "fixed"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + assert.ok(result.requestId); + + const result_release = await fileLeaseClient.releaseLease(); + assert.equal( + result_release._response.request.headers.get("x-ms-client-request-id"), + result_release._response.request.requestId + ); + }); + + it("acquireLease_available_NoproposedLeaseId_infinite @loki @sql", async () => { + const leaseResult = await fileLeaseClient.acquireLease(-1); + const leaseId = leaseResult.leaseId; + assert.ok(leaseId); + + const result = await fileClient.getProperties(); + assert.equal(result.leaseDuration, "infinite"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + + await fileLeaseClient.releaseLease(); + }); + + it("releaseLease @loki @sql", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = -1; + fileLeaseClient = await fileClient.getDataLakeLeaseClient(guid); + await fileLeaseClient.acquireLease(duration); + + let result = await fileClient.getProperties(); + assert.equal(result.leaseDuration, "infinite"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + + await fileLeaseClient.releaseLease(); + result = await fileClient.getProperties(); + assert.equal(result.leaseDuration, undefined); + assert.equal(result.leaseState, "available"); + assert.equal(result.leaseStatus, "unlocked"); + }); + + it("renewLease @loki @sql", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = 15; + fileLeaseClient = await fileClient.getDataLakeLeaseClient(guid); + await fileLeaseClient.acquireLease(duration); + + const result = await fileClient.getProperties(); + assert.equal(result.leaseDuration, "fixed"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + + await sleep(16 * 1000); + const result2 = await fileClient.getProperties(); + assert.ok(!result2.leaseDuration); + assert.equal(result2.leaseState, "expired"); + assert.equal(result2.leaseStatus, "unlocked"); + + await fileLeaseClient.renewLease(); + + const result3 = await fileClient.getProperties(); + assert.equal(result3.leaseDuration, "fixed"); + assert.equal(result3.leaseState, "leased"); + assert.equal(result3.leaseStatus, "locked"); + + await fileLeaseClient.releaseLease(); + }); + + it("changeLease @loki @sql", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = 15; + fileLeaseClient = fileClient.getDataLakeLeaseClient(guid); + await fileLeaseClient.acquireLease(duration); + + const result = await fileClient.getProperties(); + assert.equal(result.leaseDuration, "fixed"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + + const newGuid = "3c7e72ebb4304526bc53d8ecef03798f"; + const result_change = await fileLeaseClient.changeLease(newGuid); + assert.equal( + result_change._response.request.headers.get("x-ms-client-request-id"), + result_change._response.request.requestId + ); + + await fileClient.getProperties(); + await fileLeaseClient.releaseLease(); + }); + + it("breakLease @loki @sql", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = 15; + fileLeaseClient = fileClient.getDataLakeLeaseClient(guid); + await fileLeaseClient.acquireLease(duration); + + const result = await fileClient.getProperties(); + assert.equal(result.leaseDuration, "fixed"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + + const breakDuration = 3; + let breaklefttime = breakDuration; + while (breaklefttime > 0) { + const breakResult = await fileLeaseClient.breakLease(breakDuration); + assert.equal( + breakResult._response.request.headers.get("x-ms-client-request-id"), + breakResult._response.request.requestId + ); + + assert.equal(breakResult.leaseTime! <= breaklefttime, true); + breaklefttime = breakResult.leaseTime!; + + const result2 = await fileClient.getProperties(); + assert.ok(!result2.leaseDuration); + assert.equal(result2.leaseState, "breaking"); + assert.equal(result2.leaseStatus, "locked"); + + await sleep(500); + } + + const result3 = await fileClient.getProperties(); + assert.ok(!result3.leaseDuration); + assert.equal(result3.leaseState, "broken"); + assert.equal(result3.leaseStatus, "unlocked"); + + await fileLeaseClient.releaseLease(); + const result4 = await fileClient.getProperties(); + assert.equal(result4.leaseDuration, undefined); + assert.equal(result4.leaseState, "available"); + assert.equal(result4.leaseStatus, "unlocked"); + }); + + it("should get the correct headers back when setting metadata @loki @sql", async () => { + const metadata = { + a: "a", + b: "b" + }; + const setResult = await fileClient.setMetadata(metadata); + assert.equal( + setResult._response.request.headers.get("x-ms-client-request-id"), + setResult.clientRequestId + ); + assert.notEqual(setResult.date, undefined); + assert.notEqual(setResult.etag, undefined); + assert.notEqual(setResult.isServerEncrypted, undefined); + assert.notEqual(setResult.lastModified, undefined); + assert.notEqual(setResult.requestId, undefined); + assert.notEqual(setResult.version, undefined); + const result = await fileClient.getProperties(); + assert.deepStrictEqual(result.metadata, metadata); + assert.deepStrictEqual(result.accessTier, "Hot"); + assert.deepStrictEqual(result.acceptRanges, "bytes"); + }); + + // https://docs.microsoft.com/en-us/rest/api/storageservices/get-file-properties + // as properties retrieval is implemented, the properties should be added to the tests below + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Header + it("should get the correct properties set based on set HTTP headers @loki @sql", async () => { + const cacheControl = "no-cache"; + const contentType = "text/plain; charset=UTF-8"; + const md5 = new Uint8Array([1, 2, 3, 4, 5]); + const contentEncoding = "identity"; + const contentLanguage = "en-US"; + const contentDisposition = "attachment"; + const headers: BlobHTTPHeaders = { + blobCacheControl: cacheControl, + blobContentType: contentType, + blobContentMD5: md5, + blobContentDisposition: contentDisposition, + blobContentLanguage: contentLanguage, + blobContentEncoding: contentEncoding + }; + const result_set = await blobClient.setHTTPHeaders(headers); + assert.equal( + result_set._response.request.headers.get("x-ms-client-request-id"), + result_set.clientRequestId + ); + const result = await fileClient.getProperties(); + assert.deepStrictEqual(result.cacheControl, cacheControl); + assert.deepStrictEqual(result.contentType, contentType); + assert.deepEqual(result.contentMD5, md5); + assert.deepStrictEqual(result.contentDisposition, contentDisposition); + assert.deepStrictEqual(result.contentLanguage, contentLanguage); + }); + + it("setHTTPHeaders with default parameters @loki @sql", async () => { + await blobClient.setHTTPHeaders({}); + const result = await fileClient.getProperties(); + + assert.ok(result.lastModified); + assert.deepStrictEqual(result.metadata, {}); + assert.ok(!result.cacheControl); + assert.ok(!result.contentType); + assert.ok(!result.contentMD5); + assert.ok(!result.contentEncoding); + assert.ok(!result.contentLanguage); + assert.ok(!result.contentDisposition); + }); + + it("setHTTPHeaders with all parameters set @loki @sql", async () => { + const headers: BlobHTTPHeaders = { + blobCacheControl: "fileCacheControl", + blobContentDisposition: "fileContentDisposition", + blobContentEncoding: "fileContentEncoding", + blobContentLanguage: "fileContentLanguage", + blobContentMD5: isNode + ? Buffer.from([1, 2, 3, 4]) + : new Uint8Array([1, 2, 3, 4]), + blobContentType: "fileContentType" + }; + await blobClient.setHTTPHeaders(headers); + const result = await fileClient.getProperties(); + assert.ok(result.date); + assert.ok(result.lastModified); + assert.deepStrictEqual(result.metadata, {}); + assert.deepStrictEqual(result.cacheControl, headers.blobCacheControl); + assert.deepStrictEqual(result.contentType, headers.blobContentType); + assert.deepStrictEqual(result.contentMD5, headers.blobContentMD5); + assert.deepStrictEqual(result.contentEncoding, headers.blobContentEncoding); + assert.deepStrictEqual(result.contentLanguage, headers.blobContentLanguage); + assert.deepStrictEqual( + result.contentDisposition, + headers.blobContentDisposition + ); + }); + + it("Copy file should work @loki @sql", async () => { + const sourcefile = getUniqueName("file"); + const destfile = getUniqueName("file"); + + const sourceBlobClient = containerClient.getBlobClient(sourcefile); + const destBlobClient = containerClient.getBlobClient(destfile); + const sourceFileClient = fileSystemClient.getFileClient(sourcefile); + const destfileClient = fileSystemClient.getFileClient(destfile); + + const metadata = { key: "value" }; + const pathHttpHeaders = { + cacheControl: "fileCacheControl", + contentDisposition: "fileContentDisposition", + contentEncoding: "fileContentEncoding", + contentLanguage: "fileContentLanguage", + contentType: "fileContentType" + }; + + await upload(sourceFileClient, "hello", { pathHttpHeaders, metadata }); + + const result_startcopy = await destBlobClient.beginCopyFromURL( + sourceBlobClient.url + ); + assert.equal( + result_startcopy + .getResult()! + ._response.request.headers.get("x-ms-client-request-id"), + result_startcopy.getResult()!._response.request.requestId + ); + + const result = await destfileClient.getProperties(); + assert.ok(result.date); + assert.ok(result.lastModified); + assert.deepStrictEqual(result.metadata, metadata); + assert.deepStrictEqual(result.cacheControl, pathHttpHeaders.cacheControl); + assert.deepStrictEqual(result.contentType, pathHttpHeaders.contentType); + assert.deepStrictEqual( + result.contentEncoding, + pathHttpHeaders.contentEncoding + ); + assert.deepStrictEqual( + result.contentLanguage, + pathHttpHeaders.contentLanguage + ); + assert.deepStrictEqual( + result.contentDisposition, + pathHttpHeaders.contentDisposition + ); + }); + + it("Copy file should work to override metadata @loki @sql", async () => { + const sourcefile = getUniqueName("file"); + const destfile = getUniqueName("file"); + + const sourceBlobClient = containerClient.getBlobClient(sourcefile); + const destBlobClient = containerClient.getBlobClient(destfile); + const sourceFileClient = fileSystemClient.getFileClient(sourcefile); + const destfileClient = fileSystemClient.getFileClient(destfile); + + const metadata = { key: "value" }; + const metadata2 = { key: "value2" }; + + await upload(sourceFileClient, "hello", { metadata }); + + await destBlobClient.beginCopyFromURL(sourceBlobClient.url, { + metadata: metadata2 + }); + + const result = await destfileClient.getProperties(); + assert.ok(result.date); + assert.ok(result.lastModified); + assert.deepStrictEqual(result.metadata, metadata2); + }); + + it("Copy file should not override destination Lease status @loki @sql", async () => { + const sourcefile = getUniqueName("file"); + const destfile = getUniqueName("file"); + + const sourceBlobClient = containerClient.getBlobClient(sourcefile); + const destBlobClient = containerClient.getBlobClient(destfile); + const sourceFileClient = fileSystemClient.getFileClient(sourcefile); + const destfileClient = fileSystemClient.getFileClient(destfile); + + await upload(sourceFileClient, "hello"); + await upload(destfileClient, "hello"); + + let destLeaseClient = destfileClient.getDataLakeLeaseClient(); + const leaseResult = await destLeaseClient.acquireLease(-1); + const leaseId = leaseResult.leaseId; + assert.ok(leaseId); + + const getResult = await destfileClient.getProperties(); + assert.equal(getResult.leaseDuration, "infinite"); + assert.equal(getResult.leaseState, "leased"); + assert.equal(getResult.leaseStatus, "locked"); + + await destBlobClient.beginCopyFromURL(sourceBlobClient.url, { + conditions: { leaseId } + }); + + const result = await destfileClient.getProperties(); + assert.ok(result.date); + assert.ok(result.lastModified); + assert.equal(getResult.leaseDuration, "infinite"); + assert.equal(getResult.leaseState, "leased"); + assert.equal(getResult.leaseStatus, "locked"); + + await destLeaseClient.releaseLease(); + }); + + it("Copy file should not work with ifNoneMatch * when dest exist @loki @sql", async () => { + const sourcefile = getUniqueName("file"); + const destfile = getUniqueName("file"); + + const sourceBlobClient = containerClient.getBlobClient(sourcefile); + const destBlobClient = containerClient.getBlobClient(destfile); + const sourceFileClient = fileSystemClient.getFileClient(sourcefile); + const destfileClient = fileSystemClient.getFileClient(destfile); + + const metadata = { key: "value" }; + const pathHttpHeaders = { + cacheControl: "fileCacheControl", + contentDisposition: "fileContentDisposition", + contentEncoding: "fileContentEncoding", + contentLanguage: "fileContentLanguage", + contentType: "fileContentType" + }; + + let uploadResult = await sourceFileClient.create({ + pathHttpHeaders, + metadata + }); + assert.ok(uploadResult.requestId); + await upload(sourceFileClient, "hello"); + await upload(destfileClient, "hello", { pathHttpHeaders, metadata }); + + // async copy + try { + await destBlobClient.beginCopyFromURL(sourceBlobClient.url, { + conditions: { + ifNoneMatch: "*" + } + }); + } catch (error) { + assert.deepStrictEqual(error.statusCode, 409); + return; + } + assert.fail(); + + // Sync copy + try { + await destBlobClient.syncCopyFromURL(sourceBlobClient.url, { + conditions: { + ifNoneMatch: "*" + } + }); + } catch (error) { + assert.deepStrictEqual(error.statusCode, 409); + return; + } + assert.fail(); + }); + + it("Synchronized copy file should work @loki @sql", async () => { + const sourcefile = getUniqueName("file"); + const destfile = getUniqueName("file"); + + const sourceBlobClient = containerClient.getBlobClient(sourcefile); + const destBlobClient = containerClient.getBlobClient(destfile); + const sourceFileClient = fileSystemClient.getFileClient(sourcefile); + const destfileClient = fileSystemClient.getFileClient(destfile); + + const metadata = { key: "value" }; + const pathHttpHeaders = { + cacheControl: "fileCacheControl", + contentDisposition: "fileContentDisposition", + contentEncoding: "fileContentEncoding", + contentLanguage: "fileContentLanguage", + contentType: "fileContentType" + }; + + await upload(sourceFileClient, "hello", { pathHttpHeaders, metadata }); + const result_copy = await destBlobClient.syncCopyFromURL( + sourceBlobClient.url + ); + assert.equal( + result_copy._response.request.headers.get("x-ms-client-request-id"), + result_copy._response.request.requestId + ); + assert.equal(result_copy.copyStatus, "success"); + + const result = await destfileClient.getProperties(); + assert.ok(result.date); + assert.ok(result.lastModified); + assert.deepStrictEqual(result.metadata, metadata); + assert.deepStrictEqual(result.cacheControl, pathHttpHeaders.cacheControl); + assert.deepStrictEqual(result.contentType, pathHttpHeaders.contentType); + assert.deepStrictEqual( + result.contentEncoding, + pathHttpHeaders.contentEncoding + ); + assert.deepStrictEqual( + result.contentLanguage, + pathHttpHeaders.contentLanguage + ); + assert.deepStrictEqual( + result.contentDisposition, + pathHttpHeaders.contentDisposition + ); + }); + + it("Synchronized copy file should work to override metadata @loki @sql", async () => { + const sourcefile = getUniqueName("file"); + const destfile = getUniqueName("file"); + + const sourceBlobClient = containerClient.getBlobClient(sourcefile); + const destBlobClient = containerClient.getBlobClient(destfile); + const sourceFileClient = fileSystemClient.getFileClient(sourcefile); + const destfileClient = fileSystemClient.getFileClient(destfile); + + const metadata = { key: "value" }; + const metadata2 = { key: "value2" }; + + const pathHttpHeaders = { + cacheControl: "fileCacheControl", + contentDisposition: "fileContentDisposition", + contentEncoding: "fileContentEncoding", + contentLanguage: "fileContentLanguage", + contentType: "fileContentType" + }; + + await upload(sourceFileClient, "hello", { pathHttpHeaders, metadata }); + await destBlobClient.syncCopyFromURL(sourceBlobClient.url, { + metadata: metadata2 + }); + + const result = await destfileClient.getProperties(); + assert.ok(result.date); + assert.ok(result.lastModified); + assert.deepStrictEqual(result.metadata, metadata2); + }); + + it("Synchronized copy file should not override destination Lease status @loki @sql", async () => { + const sourcefile = getUniqueName("file"); + const destfile = getUniqueName("file"); + + const sourceBlobClient = containerClient.getBlobClient(sourcefile); + const destBlobClient = containerClient.getBlobClient(destfile); + const sourceFileClient = fileSystemClient.getFileClient(sourcefile); + const destfileClient = fileSystemClient.getFileClient(destfile); + + await upload(sourceFileClient, "hello"); + await upload(destfileClient, "hello"); + + let destLeaseClient = destfileClient.getDataLakeLeaseClient(); + const leaseResult = await destLeaseClient.acquireLease(-1); + const leaseId = leaseResult.leaseId; + assert.ok(leaseId); + + const getResult = await destfileClient.getProperties(); + assert.equal(getResult.leaseDuration, "infinite"); + assert.equal(getResult.leaseState, "leased"); + assert.equal(getResult.leaseStatus, "locked"); + + await destBlobClient.syncCopyFromURL(sourceBlobClient.url, { + conditions: { leaseId } + }); + + const result = await destfileClient.getProperties(); + assert.ok(result.date); + assert.ok(result.lastModified); + assert.equal(getResult.leaseDuration, "infinite"); + assert.equal(getResult.leaseState, "leased"); + assert.equal(getResult.leaseStatus, "locked"); + + await destLeaseClient.releaseLease(); + }); + + it("Synchronized copy file should work for page file @loki @sql", async () => { + const sourcefile = getUniqueName("file"); + const destfile = getUniqueName("file"); + + const sourceBlobClient = containerClient.getBlobClient(sourcefile); + const destBlobClient = containerClient.getBlobClient(destfile); + const sourceFileClient = fileSystemClient.getFileClient(sourcefile); + const destfileClient = fileSystemClient.getFileClient(destfile); + + const metadata = { key: "value" }; + + const pathHttpHeaders = { + cacheControl: "fileCacheControl", + contentDisposition: "fileContentDisposition", + contentEncoding: "fileContentEncoding", + contentLanguage: "fileContentLanguage", + contentType: "fileContentType" + }; + + await upload(sourceFileClient, "hello", { pathHttpHeaders, metadata }); + const result_copy = await destBlobClient.syncCopyFromURL( + sourceBlobClient.url + ); + assert.equal( + result_copy._response.request.headers.get("x-ms-client-request-id"), + result_copy._response.request.requestId + ); + assert.equal(result_copy.copyStatus, "success"); + + const result = await destfileClient.getProperties(); + assert.ok(result.date); + assert.ok(result.lastModified); + assert.deepStrictEqual(result.metadata, metadata); + assert.deepStrictEqual(result.cacheControl, pathHttpHeaders.cacheControl); + assert.deepStrictEqual(result.contentType, pathHttpHeaders.contentType); + assert.deepStrictEqual( + result.contentEncoding, + pathHttpHeaders.contentEncoding + ); + assert.deepStrictEqual( + result.contentLanguage, + pathHttpHeaders.contentLanguage + ); + assert.deepStrictEqual( + result.contentDisposition, + pathHttpHeaders.contentDisposition + ); + }); + + it("Acquire Lease on Breaking Lease status, if LeaseId not match, throw LeaseIdMismatchWithLease error @loki @sql", async () => { + // TODO: implement the case later + }); + + it("Renew Lease on Breaking Lease status, if LeaseId not match, throw LeaseIdMismatchWithLease error @loki @sql", async () => { + // TODO: implement the case later + }); + + it("Change Lease on Breaking Lease status, if LeaseId not match, throw LeaseIdMismatchWithLease error @loki @sql", async () => { + // TODO: implement the case later + }); + + it("Renew: Lease on Breaking Lease status, if LeaseId not match, throw LeaseIdMismatchWithLease error @loki @sql", async () => { + // TODO: implement the case later + }); + + it("Acquire Lease on Broken Lease status, if LeaseId not match, throw LeaseIdMismatchWithLease error @loki @sql", async () => { + // TODO: implement the case later + }); + + it("Break Lease on Infinite Lease, if give valid breakPeriod, should be broken after breadperiod @loki @sql", async () => { + // TODO: implement the case later + }); + + it("Break Lease on Infinite Lease, if not give breakPeriod, should be broken immidiately @loki @sql", async () => { + // TODO: implement the case later + }); + + it("Renew: Lease on Leased status, if LeaseId not match, throw LeaseIdMismatchWithLease error @loki @sql", async () => { + // TODO: implement the case later + }); + + it("Change Lease on Leased status, if input LeaseId not match anyone of leaseID or proposedLeaseId, throw LeaseIdMismatchWithLease error @loki @sql", async () => { + // TODO: implement the case later + }); + + it("Change Lease on Leased status, if input LeaseId matches proposedLeaseId, will change success @loki @sql", async () => { + // TODO: implement the case later + }); + + it("UploadPage on a Leased page file, if input LeaseId matches, will success @loki @sql", async () => { + // TODO: implement the case later + }); + + it("ClearPage on a Leased page file, if input LeaseId matches, will success @loki @sql", async () => { + // TODO: implement the case later + }); + + it("Resize a Leased page file, if input LeaseId matches, will success @loki @sql", async () => { + // TODO: implement the case later + }); + + it("UpdateSequenceNumber a Leased page file, if input LeaseId matches, will success @loki @sql", async () => { + // TODO: implement the case later + }); +}); diff --git a/tests/dfs/apis/filesystem.test.ts b/tests/dfs/apis/filesystem.test.ts new file mode 100644 index 000000000..098874326 --- /dev/null +++ b/tests/dfs/apis/filesystem.test.ts @@ -0,0 +1,1205 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { Context } from "mocha"; + +import { + DataLakeDirectoryClient, + DataLakeFileClient, + DataLakeFileSystemClient, + DataLakeServiceClient, + FileSystemListDeletedPathsResponse, + FileSystemListPathsResponse, + StorageSharedKeyCredential +} from "@azure/storage-file-datalake"; + +import { configLogger } from "../../../src/common/Logger"; +import { + EMULATOR_ACCOUNT_KEY, + EMULATOR_ACCOUNT_NAME, + getEncryptionScope, + getUniqueName, + getYieldedValue +} from "../../testutils"; + +import assert = require("assert"); +import BlobTestServerFactory from "../../BlobTestServerFactory"; + +// Set true to enable debug log +configLogger(false); + +describe("DataLakeFileSystemClient", () => { + const factory = new BlobTestServerFactory(true); + const server = factory.createServer(); + + const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`; + const serviceClient = new DataLakeServiceClient( + baseURL, + new StorageSharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + + let fileSystemName: string; + let fileSystemClient: DataLakeFileSystemClient; + + before(async () => { + await server.start(); + }); + + after(async () => { + await server.close(); + await server.clean(); + }); + + beforeEach(async function (this: Context) { + checkIfShouldSkip(this); + fileSystemName = getUniqueName("filesystem"); + fileSystemClient = serviceClient.getFileSystemClient(fileSystemName); + await fileSystemClient.createIfNotExists(); + }); + + afterEach(async () => { + await fileSystemClient.deleteIfExists(); + }); + + it("setMetadata @loki @sql", async () => { + const metadata = { + key0: "val0", + keya: "vala", + keyb: "valb" + }; + await fileSystemClient.setMetadata(metadata); + + const result = await fileSystemClient.getProperties(); + assert.deepEqual(result.metadata, metadata); + }); + + it("setMetadata with tracing @loki @sql", async () => { + const metadata = { + key0: "val0", + keya: "vala", + keyb: "valb" + }; + await fileSystemClient.setMetadata(metadata); + }); + + it("getProperties @loki @sql", async () => { + const result = await fileSystemClient.getProperties(); + assert.ok(result.etag!.length > 0); + assert.ok(result.lastModified); + assert.ok(!result.leaseDuration); + assert.equal(result.leaseState, "available"); + assert.equal(result.leaseStatus, "unlocked"); + assert.ok(result.requestId); + assert.ok(result.version); + assert.ok(result.date); + assert.ok(!result.publicAccess); + assert.ok(result.clientRequestId); // As default pipeline involves UniqueRequestIDPolicy + }); + + it("create with default parameters @loki @sql", (done) => { + // create() with default parameters has been tested in beforeEach + done(); + }); + + it("create with all parameters configured @loki @sql", async () => { + const cClient = serviceClient.getFileSystemClient( + getUniqueName(fileSystemName) + ); + const metadata = { key: "value" }; + const access = "filesystem"; + await cClient.create({ metadata, access }); + const result = await cClient.getProperties(); + assert.deepEqual(result.publicAccess, access); + assert.deepEqual(result.metadata, metadata); + }); + + it("create with encryption scope @loki @sql", async function (this: Context) { + let encryptionScopeName; + try { + encryptionScopeName = getEncryptionScope(); + } catch { + this.skip(); + } + + const cClient = serviceClient.getFileSystemClient( + getUniqueName(fileSystemName) + ); + await cClient.create({ + fileSystemEncryptionScope: { + defaultEncryptionScope: encryptionScopeName, + preventEncryptionScopeOverride: true + } + }); + const result = await cClient.getProperties(); + assert.equal(result.defaultEncryptionScope, encryptionScopeName); + await cClient.delete(); + }); + + it("create with encryption scope - preventEncryptionScopeOverride : false @loki @sql", async function (this: Context) { + let encryptionScopeName; + try { + encryptionScopeName = getEncryptionScope(); + } catch { + this.skip(); + } + + const cClient = serviceClient.getFileSystemClient( + getUniqueName(fileSystemName) + ); + await cClient.create({ + fileSystemEncryptionScope: { + defaultEncryptionScope: encryptionScopeName, + preventEncryptionScopeOverride: false + } + }); + const result = await cClient.getProperties(); + assert.equal(result.defaultEncryptionScope, encryptionScopeName); + await cClient.delete(); + }); + + it("createIfNotExists @loki @sql", async () => { + const cClient = serviceClient.getFileSystemClient( + getUniqueName(fileSystemName) + ); + const metadata = { key: "value" }; + const access = "filesystem"; + const createRes = await cClient.createIfNotExists({ metadata, access }); + assert.ok(createRes.succeeded); + assert.ok(createRes.etag); + + const createRes2 = await cClient.createIfNotExists({ metadata, access }); + assert.ok(!createRes2.succeeded); + + await cClient.deleteIfExists(); + }); + + it("deleteIfExists @loki @sql", async () => { + const cClient = serviceClient.getFileSystemClient( + getUniqueName(fileSystemName) + ); + const res = await cClient.deleteIfExists(); + assert.ok(!res.succeeded); + + await cClient.create(); + const res2 = await cClient.deleteIfExists(); + assert.ok(res2.succeeded); + }); + + it("delete @loki @sql", (done) => { + // delete() with default parameters has been tested in afterEach + done(); + }); + + it("listPaths with default parameters @loki @sql", async () => { + const recordedNow = new Date(); + + const fileClients = []; + for (let i = 0; i < 3; i++) { + const fileClient = fileSystemClient.getFileClient( + getUniqueName(`file${i}`) + ); + await fileClient.create(); + fileClients.push(fileClient); + } + + const result = (await fileSystemClient.listPaths().byPage().next()) + .value as FileSystemListPathsResponse; + + assert.deepStrictEqual(result.continuation, undefined); + assert.deepStrictEqual(result.pathItems!.length, fileClients.length); + assert.ok(fileClients[0].url.indexOf(result.pathItems![0].name!)); + + // The path is created just now, createdOn should be around but may not be the same to current time. + // assert.equal(result.pathItems![0].createdOn?.getUTCFullYear(), recordedNow.getUTCFullYear()); + // assert.equal(result.pathItems![0].createdOn?.getUTCMonth(), recordedNow.getUTCMonth()); + // assert.equal(result.pathItems![0].createdOn?.getUTCDate(), recordedNow.getUTCDate()); + // assert.equal(result.pathItems![0].createdOn?.getUTCHours(), recordedNow.getUTCHours()); + + assert.equal( + result.pathItems![0].lastModified?.getUTCFullYear(), + recordedNow.getUTCFullYear() + ); + assert.equal( + result.pathItems![0].lastModified?.getUTCMonth(), + recordedNow.getUTCMonth() + ); + assert.equal( + result.pathItems![0].lastModified?.getUTCDate(), + recordedNow.getUTCDate() + ); + assert.equal( + result.pathItems![0].lastModified?.getUTCHours(), + recordedNow.getUTCHours() + ); + + for (const file of fileClients) { + await file.delete(); + } + }); + + it("listPaths - Encryption Scope @loki @sql", async function (this: Context) { + let encryptionScopeName; + try { + encryptionScopeName = getEncryptionScope(); + } catch { + this.skip(); + } + + const cClient = serviceClient.getFileSystemClient( + getUniqueName(fileSystemName) + ); + await cClient.create({ + fileSystemEncryptionScope: { + defaultEncryptionScope: encryptionScopeName, + preventEncryptionScopeOverride: true + } + }); + + const fileClient = cClient.getFileClient(getUniqueName(`file`)); + await fileClient.create(); + + const dirClient = cClient.getFileClient(getUniqueName(`dir`)); + await dirClient.create(); + + const result = (await cClient.listPaths().byPage().next()) + .value as FileSystemListPathsResponse; + + assert.equal(result.pathItems!.length, 2); + assert.equal(result.pathItems![0].encryptionScope, encryptionScopeName); + assert.equal(result.pathItems![1].encryptionScope, encryptionScopeName); + + await fileClient.delete(); + await dirClient.delete(); + }); + + it("listPaths - PagedAsyncIterableIterator with Encryption Scope @loki @sql", async function (this: Context) { + let encryptionScopeName; + try { + encryptionScopeName = getEncryptionScope(); + } catch { + this.skip(); + } + + const cClient = serviceClient.getFileSystemClient( + getUniqueName(fileSystemName) + ); + await cClient.create({ + fileSystemEncryptionScope: { + defaultEncryptionScope: encryptionScopeName, + preventEncryptionScopeOverride: true + } + }); + + const fileClient = cClient.getFileClient(getUniqueName(`file`)); + await fileClient.create(); + const dirClient = cClient.getFileClient(getUniqueName(`dir`)); + await dirClient.create(); + + for await (const listedFile of cClient.listPaths()) { + assert.equal(listedFile.encryptionScope, encryptionScopeName); + } + + await fileClient.delete(); + await dirClient.delete(); + }); + + it("listPaths - ExpiryTime, NeverExpire @loki @sql", async function (this: Context) { + const fileClient = fileSystemClient.getFileClient(getUniqueName(`file`)); + await fileClient.create(); + await fileClient.setExpiry("NeverExpire"); + const result = (await fileSystemClient.listPaths().byPage().next()) + .value as FileSystemListPathsResponse; + + assert.equal(result.pathItems![0].expiresOn, undefined); + await fileClient.delete(); + }); + + it.skip("listPaths - ExpiryTime, Absolute [listPaths don't return expiresOn in the spec and adding it make some other sdks fail] @loki @sql", async function (this: Context) { + const now = new Date(); + const delta = 30 * 1000; + const expiresOn = new Date(now.getTime() + delta); + const fileClient = fileSystemClient.getFileClient(getUniqueName(`file`)); + + const content = "Hello, World"; + await fileClient.create(); + await fileClient.append(content, 0, content.length); + await fileClient.flush(content.length); + // const clock = useFakeTimers(now); + let setExpiryPromise: Promise; + try { + setExpiryPromise = fileClient.setExpiry("Absolute", { expiresOn }); + } finally { + // clock.restore(); + } + await setExpiryPromise; + + const result = (await fileSystemClient.listPaths().byPage().next()) + .value as FileSystemListPathsResponse; + + const recordedExpiresOn = new Date(expiresOn.getTime()); + recordedExpiresOn.setMilliseconds(0); // milliseconds dropped + assert.equal( + result.pathItems![0].expiresOn?.getTime(), + recordedExpiresOn.getTime() + ); + await fileClient.delete(); + }); + + it.skip("listPaths - ExpiryTime, RelativeToNow [listPaths don't return expiresOn in the spec and adding it make some other sdks fail] @loki @sql", async () => { + const delta = 30 * 1000; + const fileClient = fileSystemClient.getFileClient(getUniqueName(`file`)); + + const content = "Hello, World"; + await fileClient.create(); + await fileClient.append(content, 0, content.length); + await fileClient.flush(content.length); + await fileClient.setExpiry("RelativeToNow", { timeToExpireInMs: delta }); + + const result = (await fileSystemClient.listPaths().byPage().next()) + .value as FileSystemListPathsResponse; + + assert.ok(result.pathItems![0].expiresOn); + await fileClient.delete(); + }); + + it.skip("listPaths - ExpiryTime, RelativeToCreation [listPaths don't return expiresOn in the spec and adding it make some other sdks fail] @loki @sql", async () => { + const delta = 1000 * 3600 + 0.12; + const fileClient = fileSystemClient.getFileClient(getUniqueName(`file`)); + + const content = "Hello, World"; + await fileClient.create(); + await fileClient.append(content, 0, content.length); + await fileClient.flush(content.length); + await fileClient.setExpiry("RelativeToCreation", { + timeToExpireInMs: delta + }); + + const result = (await fileSystemClient.listPaths().byPage().next()) + .value as FileSystemListPathsResponse; + assert.equal( + result.pathItems![0].expiresOn?.getTime(), + result.pathItems![0].createdOn!.getTime() + Math.round(delta) + ); + await fileClient.delete(); + }); + + it("listPaths with default parameters - null path shouldn't throw error @loki @sql", async () => { + const fileClients = []; + for (let i = 0; i < 3; i++) { + const fileClient = fileSystemClient.getFileClient( + getUniqueName(`file${i}`) + ); + + await fileClient.create(); + fileClients.push(fileClient); + } + + const result = ( + await fileSystemClient.listPaths({ path: "" }).byPage().next() + ).value; + assert.deepStrictEqual(result.continuation, undefined); + assert.deepStrictEqual(result.pathItems!.length, fileClients.length); + assert.ok(fileClients[0].url.indexOf(result.pathItems![0].name)); + + for (const file of fileClients) { + await file.delete(); + } + }); + + it("listPaths with all parameters configured @loki @sql", async () => { + const fileClients = []; + const prefix = "file"; + const metadata = { + keya: "a", + keyb: "c" + }; + for (let i = 0; i < 2; i++) { + const fileClient = fileSystemClient.getFileClient( + getUniqueName(`${prefix}${i}`) + ); + + await fileClient.create({ + metadata: metadata + }); + fileClients.push(fileClient); + } + + const result = ( + await fileSystemClient + .listPaths({ + userPrincipalName: true, + recursive: true, + path: "" + }) + .byPage({ maxPageSize: 1 }) + .next() + ).value as FileSystemListPathsResponse; + + assert.deepStrictEqual(result.pathItems!.length, 1); + assert.ok(fileClients[0].url.indexOf(result.pathItems![0].name!)); + + const result2 = ( + await fileSystemClient + .listPaths({ + userPrincipalName: true, + recursive: true, + path: "" + }) + .byPage({ continuationToken: result.continuation, maxPageSize: 2 }) + .next() + ).value; + + assert.deepStrictEqual(result2.pathItems!.length, 1); + assert.ok(fileClients[0].url.indexOf(result2.pathItems![0].name)); + + for (const file of fileClients) { + await file.delete(); + } + }); + + it("Verify PagedAsyncIterableIterator for listPaths @loki @sql", async () => { + const fileClients = []; + const prefix = "file"; + const metadata = { + keya: "a", + keyb: "c" + }; + for (let i = 0; i < 4; i++) { + const fileClient = fileSystemClient.getFileClient( + getUniqueName(`${prefix}${i}`) + ); + + await fileClient.create({ + metadata + }); + fileClients.push(fileClient); + } + + let i = 0; + for await (const file of fileSystemClient.listPaths({ + userPrincipalName: true, + recursive: true, + path: "" + })) { + assert.ok(fileClients[i].url.indexOf(file.name!)); + i++; + } + + for (const file of fileClients) { + await file.delete(); + } + }); + + it("Verify PagedAsyncIterableIterator(generator .next() syntax) for listPaths @loki @sql", async () => { + const fileClients = []; + const prefix = "file"; + const metadata = { + keya: "a", + keyb: "c" + }; + for (let i = 0; i < 2; i++) { + const fileClient = fileSystemClient.getFileClient( + getUniqueName(`${prefix}${i}`) + ); + + await fileClient.create({ + metadata + }); + fileClients.push(fileClient); + } + + const iterator = fileSystemClient.listPaths({ + userPrincipalName: true, + recursive: true, + path: "" + }); + + let path = getYieldedValue(await iterator.next()); + assert.ok(fileClients[0].url.indexOf(path.name!)); + + path = getYieldedValue(await iterator.next()); + assert.ok(fileClients[1].url.indexOf(path.name!)); + + for (const file of fileClients) { + await file.delete(); + } + }); + + it("Verify PagedAsyncIterableIterator(byPage()) for listPaths @loki @sql", async () => { + const fileClients = []; + const prefix = "file"; + const metadata = { + keya: "a", + keyb: "c" + }; + for (let i = 0; i < 4; i++) { + const fileClient = fileSystemClient.getFileClient( + getUniqueName(`${prefix}${i}`) + ); + + await fileClient.create({ + metadata + }); + fileClients.push(fileClient); + } + + let i = 0; + for await (const response of fileSystemClient + .listPaths({ + userPrincipalName: true, + recursive: true, + path: "" + }) + .byPage({ maxPageSize: 2 })) { + for (const file of response.pathItems || []) { + assert.ok(fileClients[i].url.indexOf(file.name!)); + i++; + } + } + + for (const file of fileClients) { + await file.delete(); + } + }); + + it("Verify PagedAsyncIterableIterator(byPage() - continuationToken) for listPaths @loki @sql", async () => { + const fileClients = []; + const prefix = "file"; + const metadata = { + keya: "a", + keyb: "c" + }; + for (let i = 0; i < 4; i++) { + const fileClient = fileSystemClient.getFileClient( + getUniqueName(`${prefix}${i}`) + ); + + await fileClient.create({ + metadata + }); + fileClients.push(fileClient); + } + + let i = 0; + let iter = fileSystemClient + .listPaths({ + userPrincipalName: true, + recursive: true, + path: "" + }) + .byPage({ maxPageSize: 2 }); + let response = (await iter.next()).value; + for (const file of response.pathItems) { + assert.ok(fileClients[i].url.indexOf(file.name)); + i++; + } + // Gets next marker + const marker = response.continuationToken; + // Passing next marker as continuationToken + iter = fileSystemClient + .listPaths({ + userPrincipalName: true, + recursive: true, + path: "" + }) + .byPage({ continuationToken: marker, maxPageSize: 2 }); + response = (await iter.next()).value; + // Gets 2 blobs + for (const file of response.pathItems) { + assert.ok(fileClients[i].url.indexOf(file.name)); + i++; + } + + for (const file of fileClients) { + await file.delete(); + } + }); + + it("verify fileSystemName passed to the client @loki @sql", async () => { + const accountName = "myaccount"; + const newClient = new DataLakeFileSystemClient( + `https://${accountName}.dfs.core.windows.net/` + fileSystemName + ); + assert.equal( + newClient.name, + fileSystemName, + "File system name is not the same as the one provided." + ); + assert.equal( + newClient.accountName, + accountName, + "Account name is not the same as the one provided." + ); + }); + + it("exists returns true on an existing file system @loki @sql", async () => { + const result = await fileSystemClient.exists(); + assert.ok( + result, + "exists() should return true for an existing file system" + ); + }); + + it("exists returns false on non-existing file system @loki @sql", async () => { + const newFileSystemClient = serviceClient.getFileSystemClient( + getUniqueName("newfilesystem") + ); + const result = await newFileSystemClient.exists(); + assert.ok( + result === false, + "exists() should returns false on non-existing file system" + ); + }); +}); + +describe("DataLakeFileSystemClient with soft delete", () => { + const factory = new BlobTestServerFactory(true); + const server = factory.createServer(); + + const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`; + const serviceClient = new DataLakeServiceClient( + baseURL, + new StorageSharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + + let fileSystemClient: DataLakeFileSystemClient; + + before(async () => { + await server.start(); + }); + + after(async () => { + await server.close(); + await server.clean(); + }); + + beforeEach(async function (this: Context) { + checkIfShouldSkip(this); + + // try { + // serviceClient = getGenericDataLakeServiceClient(recorder, "DFS_SOFT_DELETE_"); + // } catch (err: any) { + // this.skip(); + // } + + fileSystemClient = serviceClient.getFileSystemClient( + getUniqueName(`filesystem`) + ); + await fileSystemClient.createIfNotExists(); + }); + + afterEach(async function () { + if (fileSystemClient) { + await fileSystemClient.deleteIfExists(); + } + }); + + it("listDeletedPaths with default parameters @loki @sql", async () => { + const fileClients = []; + for (let i = 0; i < 3; i++) { + const fileClient = fileSystemClient.getFileClient( + getUniqueName(`file${i}`) + ); + await fileClient.create(); + fileClients.push(fileClient); + } + + for (const file of fileClients) { + await file.delete(); + } + + const result = (await fileSystemClient.listDeletedPaths().byPage().next()) + .value as FileSystemListDeletedPathsResponse; + + assert.deepStrictEqual(result.continuation, undefined); + assert.deepStrictEqual(result.pathItems!.length, fileClients.length); + assert.ok(fileClients[0].url.indexOf(result.pathItems![0].name)); + + for (const pathItem of result.pathItems!) { + assert.ok(pathItem.deletedOn); + assert.ok(pathItem.deletionId); + assert.ok(pathItem.remainingRetentionDays); + } + }); + + it("listDeletedPaths and listPaths with recreating file after deletion @loki @sql", async () => { + const fileClients = []; + for (let i = 0; i < 3; i++) { + const fileClient = fileSystemClient.getFileClient( + getUniqueName(`file${i}`) + ); + await fileClient.create(); + fileClients.push(fileClient); + } + + for (const file of fileClients) { + await file.delete(); + await file.create(); + } + + const result = (await fileSystemClient.listDeletedPaths().byPage().next()) + .value as FileSystemListDeletedPathsResponse; + + assert.deepStrictEqual(result.continuation, undefined); + assert.deepStrictEqual(result.pathItems!.length, fileClients.length); + assert.ok(fileClients[0].url.indexOf(result.pathItems![0].name)); + + for (const pathItem of result.pathItems!) { + assert.ok(pathItem.deletedOn); + assert.ok(pathItem.deletionId); + assert.ok(pathItem.remainingRetentionDays); + } + + const listPathResult = (await fileSystemClient.listPaths().byPage().next()) + .value as FileSystemListPathsResponse; + + assert.deepStrictEqual(listPathResult.continuation, undefined); + assert.deepStrictEqual( + listPathResult.pathItems!.length, + fileClients.length + ); + assert.ok(fileClients[0].url.indexOf(listPathResult.pathItems![0].name!)); + }); + + it("listDeletedPaths with recreating and deletion again @loki @sql", async () => { + const fileClients = []; + for (let i = 0; i < 3; i++) { + const fileClient = fileSystemClient.getFileClient( + getUniqueName(`file${i}`) + ); + await fileClient.create(); + fileClients.push(fileClient); + } + + for (const file of fileClients) { + await file.delete(); + await file.create(); + await file.delete(); + } + + const result = (await fileSystemClient.listDeletedPaths().byPage().next()) + .value as FileSystemListDeletedPathsResponse; + + assert.deepStrictEqual(result.continuation, undefined); + assert.deepStrictEqual(result.pathItems!.length, 2 * fileClients.length); + assert.ok(fileClients[0].url.indexOf(result.pathItems![0].name)); + + for (const pathItem of result.pathItems!) { + assert.ok(pathItem.deletedOn); + assert.ok(pathItem.deletionId); + assert.ok(pathItem.remainingRetentionDays); + } + }); + + it("listDeletedPaths with default parameters - empty path shouldn't throw error @loki @sql", async () => { + const fileClients = []; + for (let i = 0; i < 3; i++) { + const fileClient = fileSystemClient.getFileClient( + getUniqueName(`file${i}`) + ); + + await fileClient.create(); + fileClients.push(fileClient); + } + + for (const file of fileClients) { + await file.delete(); + } + + const result = ( + await fileSystemClient.listDeletedPaths({ prefix: "" }).byPage().next() + ).value; + + assert.deepStrictEqual(result.continuation, undefined); + assert.deepStrictEqual(result.pathItems!.length, fileClients.length); + assert.ok(fileClients[0].url.indexOf(result.pathItems![0].name)); + + for (const pathItem of result.pathItems!) { + assert.ok(pathItem.deletedOn); + assert.ok(pathItem.deletionId); + assert.ok(pathItem.remainingRetentionDays); + } + }); + + it("listDeletedPaths with all parameters configured and byPage with continuationToken @loki @sql", async () => { + const fileClients = []; + const prefix = "file"; + const metadata = { + keya: "a", + keyb: "c" + }; + for (let i = 0; i < 2; i++) { + const fileClient = fileSystemClient.getFileClient( + getUniqueName(`${prefix}${i}`) + ); + + await fileClient.create({ + metadata: metadata + }); + fileClients.push(fileClient); + } + + for (const file of fileClients) { + await file.delete(); + } + + const result = ( + await fileSystemClient + .listDeletedPaths({ + prefix: "" + }) + .byPage({ maxPageSize: 1 }) + .next() + ).value as FileSystemListDeletedPathsResponse; + + assert.deepStrictEqual(result.pathItems!.length, 1); + assert.ok(fileClients[0].url.indexOf(result.pathItems![0].name)); + for (const pathItem of result.pathItems!) { + assert.ok(pathItem.deletedOn); + assert.ok(pathItem.deletionId); + assert.ok(pathItem.remainingRetentionDays); + } + + const result2 = ( + await fileSystemClient + .listDeletedPaths({ + prefix: "" + }) + .byPage({ continuationToken: result.continuation, maxPageSize: 2 }) + .next() + ).value; + + assert.deepStrictEqual(result2.pathItems!.length, 1); + assert.ok(fileClients[0].url.indexOf(result2.pathItems![0].name)); + }); + + it("Verify PagedAsyncIterableIterator for listDeletedPaths @loki @sql", async () => { + const fileClients = []; + const prefix = "file"; + const metadata = { + keya: "a", + keyb: "c" + }; + for (let i = 0; i < 4; i++) { + const fileClient = fileSystemClient.getFileClient( + getUniqueName(`${prefix}${i}`) + ); + + await fileClient.create({ + metadata + }); + fileClients.push(fileClient); + } + + for (const file of fileClients) { + await file.delete(); + } + + let i = 0; + for await (const file of fileSystemClient.listDeletedPaths({ + prefix: "" + })) { + assert.ok(fileClients[i].url.indexOf(file.name)); + assert.ok(file.deletedOn); + assert.ok(file.deletionId); + assert.ok(file.remainingRetentionDays); + i++; + } + }); + + it("Verify PagedAsyncIterableIterator(generator .next() syntax) for listDeletedPaths @loki @sql", async () => { + const fileClients = []; + const prefix = "file"; + const metadata = { + keya: "a", + keyb: "c" + }; + for (let i = 0; i < 2; i++) { + const fileClient = fileSystemClient.getFileClient( + getUniqueName(`${prefix}${i}`) + ); + + await fileClient.create({ + metadata + }); + fileClients.push(fileClient); + } + + for (const file of fileClients) { + await file.delete(); + } + + const iterator = fileSystemClient.listDeletedPaths({ + prefix: "" + }); + + let path = getYieldedValue(await iterator.next()); + assert.ok(fileClients[0].url.indexOf(path.name)); + assert.ok(path.deletedOn); + assert.ok(path.deletionId); + assert.ok(path.remainingRetentionDays); + + path = getYieldedValue(await iterator.next()); + assert.ok(fileClients[1].url.indexOf(path.name)); + assert.ok(path.deletedOn); + assert.ok(path.deletionId); + assert.ok(path.remainingRetentionDays); + }); + + it("Verify PagedAsyncIterableIterator(byPage()) for listDeletedPaths @loki @sql", async () => { + const fileClients = []; + const prefix = "file"; + const metadata = { + keya: "a", + keyb: "c" + }; + for (let i = 0; i < 4; i++) { + const fileClient = fileSystemClient.getFileClient( + getUniqueName(`${prefix}${i}`) + ); + + await fileClient.create({ + metadata + }); + fileClients.push(fileClient); + } + + for (const file of fileClients) { + await file.delete(); + } + + let i = 0; + for await (const response of fileSystemClient + .listDeletedPaths({ + prefix: "" + }) + .byPage({ maxPageSize: 2 })) { + for (const file of response.pathItems || []) { + assert.ok(fileClients[i].url.indexOf(file.name)); + assert.ok(file.deletedOn); + assert.ok(file.deletionId); + assert.ok(file.remainingRetentionDays); + i++; + } + } + }); + + it("Verify PagedAsyncIterableIterator(byPage() - continuationToken) for listDeletedPaths @loki @sql", async () => { + const fileClients = []; + const prefix = "file"; + const metadata = { + keya: "a", + keyb: "c" + }; + for (let i = 0; i < 4; i++) { + const fileClient = fileSystemClient.getFileClient( + getUniqueName(`${prefix}${i}`) + ); + + await fileClient.create({ + metadata + }); + fileClients.push(fileClient); + } + + for (const file of fileClients) { + await file.delete(); + } + + let i = 0; + let iter = fileSystemClient + .listDeletedPaths({ + prefix: "" + }) + .byPage({ maxPageSize: 2 }); + let response = (await iter.next()).value; + for (const file of response.pathItems) { + assert.ok(fileClients[i].url.indexOf(file.name)); + assert.ok(file.deletedOn); + assert.ok(file.deletionId); + assert.ok(file.remainingRetentionDays); + i++; + } + // Gets next marker + const marker = response.continuationToken; + // Passing next marker as continuationToken + iter = fileSystemClient + .listDeletedPaths({ + prefix: "" + }) + .byPage({ continuationToken: marker, maxPageSize: 2 }); + response = (await iter.next()).value; + // Gets 2 blobs + for (const file of response.pathItems) { + assert.ok(fileClients[i].url.indexOf(file.name)); + assert.ok(file.deletedOn); + assert.ok(file.deletionId); + assert.ok(file.remainingRetentionDays); + i++; + } + }); + + it("Undelete file and directory @loki @sql", async () => { + const fileName = getUniqueName(`file`); + const fileClient = fileSystemClient.getFileClient(fileName); + await fileClient.create(); + const fileDeleteResponse = await fileClient.delete(); + assert.ok(fileDeleteResponse.deletionId); + + const fileundeleteResponse = await fileSystemClient.undeletePath( + fileName, + fileDeleteResponse.deletionId ?? "" + ); + + assert.ok(fileundeleteResponse.pathClient instanceof DataLakeFileClient); + + assert.ok(await fileundeleteResponse.pathClient.exists()); + await fileundeleteResponse.pathClient.delete(); + + const directoryName = getUniqueName(`directory`); + const directoryClient = fileSystemClient.getDirectoryClient(directoryName); + await directoryClient.create(); + const directoryDeleteResponse = await directoryClient.delete(); + assert.ok(directoryDeleteResponse.deletionId); + + const directoryUndeleteResponse = await fileSystemClient.undeletePath( + directoryName, + directoryDeleteResponse.deletionId ?? "" + ); + + assert.ok( + directoryUndeleteResponse.pathClient instanceof DataLakeDirectoryClient + ); + + assert.ok(await directoryUndeleteResponse.pathClient.exists()); + await directoryUndeleteResponse.pathClient.delete(); + }); + + it("Undelete file and directory - recreate and delete path and undelete the path with first deletionid @loki @sql", async () => { + const fileName = getUniqueName(`file`); + const fileClient = fileSystemClient.getFileClient(fileName); + await fileClient.create(); + const fileDeleteResponse = await fileClient.delete(); + assert.ok(fileDeleteResponse.deletionId); + const firstDeletionId = fileDeleteResponse.deletionId; + + await fileClient.create(); + await fileClient.delete(); + + const fileundeleteResponse = await fileSystemClient.undeletePath( + fileName, + firstDeletionId ?? "" + ); + + assert.ok(fileundeleteResponse.pathClient instanceof DataLakeFileClient); + + assert.ok(await fileundeleteResponse.pathClient.exists()); + await fileundeleteResponse.pathClient.delete(); + }); + + it("Undelete file and directory - recreate and delete path and undelete the path twice @loki @sql", async () => { + const fileName = getUniqueName(`file`); + const fileClient = fileSystemClient.getFileClient(fileName); + await fileClient.create(); + const firstDeleteResponse = await fileClient.delete(); + assert.ok(firstDeleteResponse.deletionId); + + await fileClient.create(); + const secondDeleteResponse = await fileClient.delete(); + assert.ok(secondDeleteResponse.deletionId); + + const fileundeleteResponse = await fileSystemClient.undeletePath( + fileName, + secondDeleteResponse.deletionId ?? "" + ); + + assert.ok(fileundeleteResponse.pathClient instanceof DataLakeFileClient); + + assert.ok(await fileundeleteResponse.pathClient.exists()); + await fileundeleteResponse.pathClient.delete(); + + try { + await fileSystemClient.undeletePath( + fileName, + firstDeleteResponse.deletionId ?? "" + ); + assert.fail("Second undeletion should fail"); + } catch (err: any) { + /* empty */ + // The test case here expects an expection, so the exception should not fail the case. + } + }); + + it("Undelete file and directory with deleteIfExists @loki @sql", async () => { + const fileName = getUniqueName(`file`); + const fileClient = fileSystemClient.getFileClient(fileName); + await fileClient.create(); + const fileDeleteResponse = await fileClient.deleteIfExists(); + assert.ok(fileDeleteResponse.deletionId); + + const fileundeleteResponse = await fileSystemClient.undeletePath( + fileName, + fileDeleteResponse.deletionId ?? "" + ); + + assert.ok(fileundeleteResponse.pathClient instanceof DataLakeFileClient); + + assert.ok(await fileundeleteResponse.pathClient.exists()); + + const directoryName = getUniqueName(`directory`); + const directoryClient = fileSystemClient.getDirectoryClient(directoryName); + await directoryClient.create(); + const directoryDeleteResponse = await directoryClient.deleteIfExists(); + assert.ok(directoryDeleteResponse.deletionId); + + const directoryUndeleteResponse = await fileSystemClient.undeletePath( + directoryName, + directoryDeleteResponse.deletionId ?? "" + ); + + assert.ok( + directoryUndeleteResponse.pathClient instanceof DataLakeDirectoryClient + ); + + assert.ok(await directoryUndeleteResponse.pathClient.exists()); + }); + + it("Undelete file and directory special char @loki @sql", async () => { + const fileNames = [ + "!'();[]@&%=+$,#äÄöÖüÜß;", + "%21%27%28%29%3B%5B%5D%40%26%25%3D%2B%24%2C%23äÄöÖüÜß%3B", + " a file or directory " + ]; + + for (const fileName of fileNames) { + const fileClient = fileSystemClient.getFileClient(fileName); + await fileClient.create(); + const fileDeleteResponse = await fileClient.delete(); + assert.ok(fileDeleteResponse.deletionId); + + const fileundeleteResponse = await fileSystemClient.undeletePath( + fileName, + fileDeleteResponse.deletionId ?? "" + ); + + assert.ok(fileundeleteResponse.pathClient instanceof DataLakeFileClient); + assert.ok(await fileundeleteResponse.pathClient.exists()); + } + }); +}); + +function checkIfShouldSkip(context: Context) { + if (context.test!.parent!.title.indexOf("soft delete") > -1) { + context.skip(); + } +} diff --git a/tests/dfs/apis/filesystemclient.test.ts b/tests/dfs/apis/filesystemclient.test.ts new file mode 100644 index 000000000..d39496867 --- /dev/null +++ b/tests/dfs/apis/filesystemclient.test.ts @@ -0,0 +1,188 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { Context } from "mocha"; + +import { TokenCredential } from "@azure/core-auth"; +import { + DataLakeFileSystemClient, + DataLakeServiceClient, + FileSystemSASPermissions, + newPipeline, + PublicAccessType, + StorageSharedKeyCredential +} from "@azure/storage-file-datalake"; + +import { + assertClientUsesTokenCredential, + EMULATOR_ACCOUNT_KEY, + EMULATOR_ACCOUNT_NAME, + getUniqueName +} from "../../testutils"; + +import assert = require("assert"); +import BlobTestServerFactory from "../../BlobTestServerFactory"; + +describe("DataLakeFileSystemClient Node.js only", () => { + const factory = new BlobTestServerFactory(true); + const server = factory.createServer(); + + const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`; + const serviceClient = new DataLakeServiceClient( + baseURL, + new StorageSharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + + let fileSystemName: string; + let fileSystemClient: DataLakeFileSystemClient; + + before(async () => { + await server.start(); + }); + + after(async () => { + await server.close(); + await server.clean(); + }); + + beforeEach(async function (this: Context) { + fileSystemName = getUniqueName("filesystem"); + fileSystemClient = serviceClient.getFileSystemClient(fileSystemName); + await fileSystemClient.createIfNotExists(); + }); + + afterEach(async function () { + await fileSystemClient.deleteIfExists(); + }); + + it("getAccessPolicy @loki @sql", async () => { + const result = await fileSystemClient.getAccessPolicy(); + assert.ok(result.etag!.length > 0); + assert.ok(result.lastModified); + assert.ok(result.requestId); + assert.ok(result.clientRequestId); + assert.ok(result.version); + assert.ok(result.date); + }); + + it("setAccessPolicy @loki @sql", async () => { + const access: PublicAccessType = "file"; + const acl = [ + { + accessPolicy: { + expiresOn: new Date("2018-12-31T11:22:33.4567890Z"), + permissions: FileSystemSASPermissions.parse("rwd").toString(), + startsOn: new Date("2017-12-31T11:22:33.4567890Z") + }, + id: "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=" + } + ]; + + await fileSystemClient.setAccessPolicy(access, acl); + const result = await fileSystemClient.getAccessPolicy(); + assert.deepEqual(result.signedIdentifiers, acl); + assert.deepEqual(result.publicAccess, access); + }); + + it("setAccessPolicy should work when expiry and start undefined @loki @sql", async () => { + const access: PublicAccessType = "file"; + const acl = [ + { + accessPolicy: { + permissions: FileSystemSASPermissions.parse("rwd").toString() + }, + id: "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=" + } + ]; + + await fileSystemClient.setAccessPolicy(access, acl); + const result = await fileSystemClient.getAccessPolicy(); + assert.deepEqual(result.signedIdentifiers, acl); + assert.deepEqual(result.publicAccess, access); + }); + + it("can be created with a url and a credential @loki @sql", async () => { + const credential = fileSystemClient.credential; + const newClient = new DataLakeFileSystemClient( + fileSystemClient.url, + credential + ); + const result = await newClient.getProperties(); + + assert.ok(result.etag!.length > 0); + assert.ok(result.lastModified); + assert.ok(!result.leaseDuration); + assert.equal(result.leaseState, "available"); + assert.equal(result.leaseStatus, "unlocked"); + assert.ok(result.requestId); + assert.ok(result.version); + assert.ok(result.date); + assert.ok(!result.publicAccess); + }); + + it("can be created with a url and a credential and an option bag @loki @sql", async () => { + const credential = fileSystemClient.credential; + const newClient = new DataLakeFileSystemClient( + fileSystemClient.url, + credential, + { + retryOptions: { + maxTries: 5 + } + } + ); + + const result = await newClient.getProperties(); + + assert.ok(result.etag!.length > 0); + assert.ok(result.lastModified); + assert.ok(!result.leaseDuration); + assert.equal(result.leaseState, "available"); + assert.equal(result.leaseStatus, "unlocked"); + assert.ok(result.requestId); + assert.ok(result.version); + assert.ok(result.date); + assert.ok(!result.publicAccess); + }); + + it("can be created with a url and a TokenCredential @loki @sql", async () => { + const tokenCredential: TokenCredential = { + getToken: () => + Promise.resolve({ + token: "token", + expiresOnTimestamp: 12345 + }) + }; + const newClient = new DataLakeFileSystemClient( + fileSystemClient.url, + tokenCredential + ); + assertClientUsesTokenCredential(newClient); + }); + + it("can be created with a url and a pipeline @loki @sql", async () => { + const credential = fileSystemClient.credential; + const pipeline = newPipeline(credential); + const newClient = new DataLakeFileSystemClient( + fileSystemClient.url, + pipeline + ); + + const result = await newClient.getProperties(); + + assert.ok(result.etag!.length > 0); + assert.ok(result.lastModified); + assert.ok(!result.leaseDuration); + assert.equal(result.leaseState, "available"); + assert.equal(result.leaseStatus, "unlocked"); + assert.ok(result.requestId); + assert.ok(result.version); + assert.ok(result.date); + assert.ok(!result.publicAccess); + }); +}); diff --git a/tests/dfs/apis/leaseclient.test.ts b/tests/dfs/apis/leaseclient.test.ts new file mode 100644 index 000000000..490105403 --- /dev/null +++ b/tests/dfs/apis/leaseclient.test.ts @@ -0,0 +1,453 @@ +// Copyright (c) Microsoft Corporation. +import assert from "assert"; +import { Context } from "mocha"; + +import { delay } from "@azure/ms-rest-js"; +// Licensed under the MIT license. +import { + DataLakeDirectoryClient, + DataLakeFileClient, + DataLakeFileSystemClient, + DataLakeServiceClient, + StorageSharedKeyCredential +} from "@azure/storage-file-datalake"; + +import { + EMULATOR_ACCOUNT_KEY, + EMULATOR_ACCOUNT_NAME, + getUniqueName +} from "../../testutils"; +import BlobTestServerFactory from "../../BlobTestServerFactory"; + +describe("LeaseClient from FileSystem", () => { + const factory = new BlobTestServerFactory(true); + const server = factory.createServer(); + + const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`; + const serviceClient = new DataLakeServiceClient( + baseURL, + new StorageSharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + + let fileSystemName: string; + let fileSystemClient: DataLakeFileSystemClient; + + before(async () => { + await server.start(); + }); + + after(async () => { + await server.close(); + await server.clean(); + }); + + beforeEach(async function (this: Context) { + fileSystemName = getUniqueName("filesystem"); + fileSystemClient = serviceClient.getFileSystemClient(fileSystemName); + await fileSystemClient.createIfNotExists(); + }); + + afterEach(async function () { + await fileSystemClient.deleteIfExists(); + }); + + it("acquireLease @loki @sql", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = 30; + const leaseClient = fileSystemClient.getDataLakeLeaseClient(guid); + await leaseClient.acquireLease(duration); + + const result = await fileSystemClient.getProperties(); + assert.equal(result.leaseDuration, "fixed"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + + await leaseClient.releaseLease(); + }); + + it("acquireLease without specifying a lease id @loki @sql", async () => { + const duration = 30; + const leaseClient = fileSystemClient.getDataLakeLeaseClient(); + await leaseClient.acquireLease(duration); + + const result = await fileSystemClient.getProperties(); + assert.equal(result.leaseDuration, "fixed"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + + await leaseClient.releaseLease(); + }); + + it("releaseLease @loki @sql", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = -1; + const leaseClient = fileSystemClient.getDataLakeLeaseClient(guid); + await leaseClient.acquireLease(duration); + + const result = await fileSystemClient.getProperties(); + assert.equal(result.leaseDuration, "infinite"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + + await leaseClient.releaseLease(); + }); + + it("renewLease @loki @sql", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = 15; + const leaseClient = fileSystemClient.getDataLakeLeaseClient(guid); + await leaseClient.acquireLease(duration); + + const result = await fileSystemClient.getProperties(); + assert.equal(result.leaseDuration, "fixed"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + + await delay(20 * 1000); + const result2 = await fileSystemClient.getProperties(); + assert.ok(!result2.leaseDuration); + assert.equal(result2.leaseState, "expired"); + assert.equal(result2.leaseStatus, "unlocked"); + + await leaseClient.renewLease(); + const result3 = await fileSystemClient.getProperties(); + assert.equal(result3.leaseDuration, "fixed"); + assert.equal(result3.leaseState, "leased"); + assert.equal(result3.leaseStatus, "locked"); + + await leaseClient.releaseLease(); + }); + + it("changeLease @loki @sql", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = 15; + const leaseClient = fileSystemClient.getDataLakeLeaseClient(guid); + await leaseClient.acquireLease(duration); + + const result = await fileSystemClient.getProperties(); + assert.equal(result.leaseDuration, "fixed"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + + const newGuid = "3c7e72ebb4304526bc53d8ecef03798f"; + await leaseClient.changeLease(newGuid); + + await fileSystemClient.getProperties(); + await leaseClient.releaseLease(); + }); + + it("breakLease @loki @sql", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = 15; + const leaseClient = fileSystemClient.getDataLakeLeaseClient(guid); + await leaseClient.acquireLease(duration); + + const result = await fileSystemClient.getProperties(); + assert.equal(result.leaseDuration, "fixed"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + + await leaseClient.breakLease(3); + + const result2 = await fileSystemClient.getProperties(); + assert.ok(!result2.leaseDuration); + assert.equal(result2.leaseState, "breaking"); + assert.equal(result2.leaseStatus, "locked"); + + await delay(3 * 1000); + + const result3 = await fileSystemClient.getProperties(); + assert.ok(!result3.leaseDuration); + assert.equal(result3.leaseState, "broken"); + assert.equal(result3.leaseStatus, "unlocked"); + }); +}); + +describe("LeaseClient from File", () => { + const factory = new BlobTestServerFactory(true); + const server = factory.createServer(); + + const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`; + const serviceClient = new DataLakeServiceClient( + baseURL, + new StorageSharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + + let fileSystemName: string; + let fileSystemClient: DataLakeFileSystemClient; + let fileName: string; + let fileClient: DataLakeFileClient; + + before(async () => { + await server.start(); + }); + + after(async () => { + await server.close(); + await server.clean(); + }); + + beforeEach(async function (this: Context) { + fileSystemName = getUniqueName("filesystem"); + fileSystemClient = serviceClient.getFileSystemClient(fileSystemName); + await fileSystemClient.createIfNotExists(); + fileName = getUniqueName("file"); + fileClient = fileSystemClient.getFileClient(fileName); + await fileClient.create(); + }); + + afterEach(async function () { + await fileSystemClient.deleteIfExists(); + }); + + it("acquireLease @loki @sql", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = 30; + const leaseClient = fileClient.getDataLakeLeaseClient(guid); + await leaseClient.acquireLease(duration); + + const result = await fileClient.getProperties(); + assert.equal(result.leaseDuration, "fixed"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + + await leaseClient.releaseLease(); + }); + + it("releaseLease @loki @sql", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = -1; + const leaseClient = fileClient.getDataLakeLeaseClient(guid); + await leaseClient.acquireLease(duration); + + const result = await fileClient.getProperties(); + assert.equal(result.leaseDuration, "infinite"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + + await leaseClient.releaseLease(); + }); + + it("renewLease @loki @sql", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = 15; + const leaseClient = fileClient.getDataLakeLeaseClient(guid); + await leaseClient.acquireLease(duration); + + const result = await fileClient.getProperties(); + assert.equal(result.leaseDuration, "fixed"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + + await delay(20 * 1000); + + const result2 = await fileClient.getProperties(); + assert.ok(!result2.leaseDuration); + assert.equal(result2.leaseState, "expired"); + // assert.equal(result2.leaseStatus, "unlocked"); // TODO: Potential bug of server which returns "locked" for "expired" lease + + await leaseClient.renewLease(); + const result3 = await fileClient.getProperties(); + assert.equal(result3.leaseDuration, "fixed"); + assert.equal(result3.leaseState, "leased"); + assert.equal(result3.leaseStatus, "locked"); + + await leaseClient.releaseLease(); + }); + + it("changeLease @loki @sql", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = 15; + const leaseClient = fileClient.getDataLakeLeaseClient(guid); + await leaseClient.acquireLease(duration); + + const result = await fileClient.getProperties(); + assert.equal(result.leaseDuration, "fixed"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + + const newGuid = "3c7e72ebb4304526bc53d8ecef03798f"; + await leaseClient.changeLease(newGuid); + + await fileClient.getProperties(); + await leaseClient.releaseLease(); + }); + + it("breakLease @loki @sql", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = 15; + const leaseClient = fileClient.getDataLakeLeaseClient(guid); + await leaseClient.acquireLease(duration); + + const result = await fileClient.getProperties(); + assert.equal(result.leaseDuration, "fixed"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + + await leaseClient.breakLease(5); + + const result2 = await fileClient.getProperties(); + assert.ok(!result2.leaseDuration); + assert.equal(result2.leaseState, "breaking"); + assert.equal(result2.leaseStatus, "locked"); + + await delay(5 * 1000); + + const result3 = await fileClient.getProperties(); + assert.ok(!result3.leaseDuration); + assert.equal(result3.leaseState, "broken"); + // assert.equal(result3.leaseStatus, "unlocked"); // TODO: Potential bug of server which returns "locked" for "broken" lease + }); +}); + +describe("LeaseClient from Directory", () => { + const factory = new BlobTestServerFactory(true); + const server = factory.createServer(); + + const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`; + const serviceClient = new DataLakeServiceClient( + baseURL, + new StorageSharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + + let fileSystemName: string; + let fileSystemClient: DataLakeFileSystemClient; + let directoryName: string; + let directoryClient: DataLakeDirectoryClient; + + before(async () => { + await server.start(); + }); + + after(async () => { + await server.close(); + await server.clean(); + }); + + beforeEach(async function (this: Context) { + fileSystemName = getUniqueName("filesystem"); + fileSystemClient = serviceClient.getFileSystemClient(fileSystemName); + await fileSystemClient.createIfNotExists(); + directoryName = getUniqueName("dir"); + directoryClient = fileSystemClient.getDirectoryClient(directoryName); + await directoryClient.create(); + }); + + afterEach(async function () { + await fileSystemClient.deleteIfExists(); + }); + + it("acquireLease @loki @sql", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = 30; + const leaseClient = directoryClient.getDataLakeLeaseClient(guid); + await leaseClient.acquireLease(duration); + + const result = await directoryClient.getProperties(); + assert.equal(result.leaseDuration, "fixed"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + + await leaseClient.releaseLease(); + }); + + it("releaseLease @loki @sql", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = -1; + const leaseClient = directoryClient.getDataLakeLeaseClient(guid); + await leaseClient.acquireLease(duration); + + const result = await directoryClient.getProperties(); + assert.equal(result.leaseDuration, "infinite"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + + await leaseClient.releaseLease(); + }); + + it("renewLease @loki @sql", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = 15; + const leaseClient = directoryClient.getDataLakeLeaseClient(guid); + await leaseClient.acquireLease(duration); + + const result = await directoryClient.getProperties(); + assert.equal(result.leaseDuration, "fixed"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + + await delay(20 * 1000); + + const result2 = await directoryClient.getProperties(); + assert.ok(!result2.leaseDuration); + assert.equal(result2.leaseState, "expired"); + // assert.equal(result2.leaseStatus, "unlocked"); // TODO: Potential bug of server which returns "locked" for "expired" lease + + await leaseClient.renewLease(); + const result3 = await directoryClient.getProperties(); + assert.equal(result3.leaseDuration, "fixed"); + assert.equal(result3.leaseState, "leased"); + assert.equal(result3.leaseStatus, "locked"); + + await leaseClient.releaseLease(); + }); + + it("changeLease @loki @sql", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = 15; + const leaseClient = directoryClient.getDataLakeLeaseClient(guid); + await leaseClient.acquireLease(duration); + + const result = await directoryClient.getProperties(); + assert.equal(result.leaseDuration, "fixed"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + + const newGuid = "3c7e72ebb4304526bc53d8ecef03798f"; + await leaseClient.changeLease(newGuid); + + await directoryClient.getProperties(); + await leaseClient.releaseLease(); + }); + + it("breakLease @loki @sql", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = 15; + const leaseClient = directoryClient.getDataLakeLeaseClient(guid); + await leaseClient.acquireLease(duration); + + const result = await directoryClient.getProperties(); + assert.equal(result.leaseDuration, "fixed"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + + await leaseClient.breakLease(15); + + const result2 = await directoryClient.getProperties(); + assert.ok(!result2.leaseDuration); + assert.equal(result2.leaseState, "breaking"); + assert.equal(result2.leaseStatus, "locked"); + + await delay(15 * 1000); + + const result3 = await directoryClient.getProperties(); + assert.ok(!result3.leaseDuration); + assert.equal(result3.leaseState, "broken"); + // assert.equal(result3.leaseStatus, "unlocked"); // TODO: Potential bug of server which returns "locked" for "broken" lease + }); +}); diff --git a/tests/dfs/apis/pathclient.test.ts b/tests/dfs/apis/pathclient.test.ts new file mode 100644 index 000000000..86b75df48 --- /dev/null +++ b/tests/dfs/apis/pathclient.test.ts @@ -0,0 +1,1857 @@ +// Copyright (c) Microsoft Corporation. +import assert from "assert"; +import { Context } from "mocha"; + +import { delay } from "@azure/ms-rest-js"; +// Licensed under the MIT license. +import { + DataLakeDirectoryClient, + DataLakeFileClient, + DataLakeFileSystemClient, + DataLakeServiceClient, + StorageSharedKeyCredential +} from "@azure/storage-file-datalake"; + +import { + bodyToString, + EMULATOR_ACCOUNT_KEY, + EMULATOR_ACCOUNT_NAME, + getEncryptionScope, + getUniqueName, + sleep, + Test_CPK_INFO +} from "../../testutils"; +import { AbortController } from "@azure/abort-controller"; +import { toPermissionsString } from "../../../src/dfs/storagefiledatalake/transforms"; +import BlobTestServerFactory from "../../BlobTestServerFactory"; + +describe("DataLakePathClient", () => { + const factory = new BlobTestServerFactory(true); + const server = factory.createServer(true); + + const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`; + const serviceClient = new DataLakeServiceClient( + baseURL, + new StorageSharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + + let fileSystemName: string; + let fileSystemClient: DataLakeFileSystemClient; + let fileName: string; + let fileClient: DataLakeFileClient; + const content = "Hello World"; + + before(async () => { + await server.start(); + }); + + after(async () => { + await server.close(); + await server.clean(); + }); + + beforeEach(async function () { + fileSystemName = getUniqueName("filesystem"); + fileSystemClient = serviceClient.getFileSystemClient(fileSystemName); + await fileSystemClient.createIfNotExists(); + fileName = getUniqueName("file"); + fileClient = fileSystemClient.getFileClient(fileName); + await fileClient.create(); + await fileClient.append(content, 0, content.length); + await fileClient.flush(content.length); + }); + + afterEach(async function () { + await fileSystemClient.deleteIfExists(); + }); + + it("DataLakeFileClient create with meta data @loki @sql", async () => { + const testFileName = getUniqueName("testfile"); + const testFileClient = fileSystemClient.getFileClient(testFileName); + const metadata = { + a: "a", + b: "b" + }; + + await testFileClient.create({ metadata: metadata }); + const result = await testFileClient.getProperties(); + assert.deepStrictEqual(result.metadata, metadata); + }); + + it("DataLakeFileClient create with permission and umark @loki @sql", async () => { + const testFileName = getUniqueName("testfile"); + const testFileClient = fileSystemClient.getFileClient(testFileName); + const permissionString = "0777"; + const umask = "0057"; + + await testFileClient.create({ + permissions: permissionString, + umask: umask + }); + const result = await testFileClient.getAccessControl(); + const permissions = { + owner: { + read: true, + write: true, + execute: true + }, + group: { + read: false, + write: true, + execute: false + }, + other: { + read: false, + write: false, + execute: false + }, + stickyBit: false, + extendedAcls: false + }; + assert.deepEqual(result.permissions, permissions); + }); + + it("DataLakeFileClient create with headers @loki @sql", async () => { + const testFileName = getUniqueName("testfile"); + const testFileClient = fileSystemClient.getFileClient(testFileName); + const httpHeader = { + cacheControl: "control", + contentEncoding: "encoding", + contentLanguage: "language", + contentDisposition: "disposition", + contentType: "type/subtype" + }; + + await testFileClient.create({ pathHttpHeaders: httpHeader }); + const result = await testFileClient.getProperties(); + assert.equal(result.cacheControl, httpHeader.cacheControl); + assert.equal(result.contentEncoding, httpHeader.contentEncoding); + assert.equal(result.contentLanguage, httpHeader.contentLanguage); + assert.equal(result.contentDisposition, httpHeader.contentDisposition); + assert.equal(result.contentType, httpHeader.contentType); + }); + + it("DataLakeFileClient create with leaseId @loki @sql", async () => { + const testFileName = getUniqueName("testfile"); + const testFileClient = fileSystemClient.getFileClient(testFileName); + const leaseId = "25180729-00c9-42b0-938b-ecabce67a007"; + const leaseDuration = 20; + + await testFileClient.create({ + proposedLeaseId: leaseId, + leaseDuration: leaseDuration + }); + const result = await testFileClient.getProperties(); + assert.equal(result.leaseDuration, "fixed"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + }); + + it("DataLakeFileClient create with relative expiry @loki @sql", async () => { + const testFileName = getUniqueName("testfile"); + const testFileClient = fileSystemClient.getFileClient(testFileName); + const timeToExpireInMs = 60 * 60 * 1000; // 1hour + await testFileClient.create({ expiresOn: timeToExpireInMs }); + const result = await testFileClient.getProperties(); + assert.equal( + result.createdOn!.getTime() + 1000 * 3600, + result.expiresOn!.getTime() + ); + }); + + it.skip("DataLakeFileClient create with absolute expiry @loki @sql", async () => { + const now = new Date(); + const delta = 2 * 1000; + const expiresOn = new Date(now.getTime() + delta); + + const testFileName = getUniqueName("testfile"); + const testFileClient = fileSystemClient.getFileClient(testFileName); + await testFileClient.create({ expiresOn: expiresOn }); + + const result = await testFileClient.getProperties(); + const recordedExpiresOn = new Date(expiresOn.getTime()); + recordedExpiresOn.setMilliseconds(0); // milliseconds dropped + assert.equal(result.expiresOn?.getTime(), recordedExpiresOn.getTime()); + + await delay(delta); + assert.ok(!(await testFileClient.exists())); + }); + + it("DataLakeFileClient create with all parameters @loki @sql", async () => { + const metadata = { + a: "a", + b: "b" + }; + + const permissionString = "0777"; + const umask = "0057"; + + const httpHeader = { + cacheControl: "control", + contentEncoding: "encoding", + contentLanguage: "language", + contentDisposition: "disposition", + contentType: "type/subtype" + }; + const leaseId = "25180729-00c9-42b0-938b-ecabce67a007"; + const leaseDuration = 20; + + const timeToExpireInMs = 60 * 1000; // 60s + + const testFileName = getUniqueName("testfile"); + const testFileClient = fileSystemClient.getFileClient(testFileName); + await testFileClient.create({ + metadata: metadata, + permissions: permissionString, + umask: umask, + pathHttpHeaders: httpHeader, + proposedLeaseId: leaseId, + leaseDuration: leaseDuration, + expiresOn: timeToExpireInMs + }); + + const result = await testFileClient.getProperties(); + assert.deepStrictEqual(result.metadata, metadata); + assert.equal( + result.createdOn!.getTime() + 1000 * 60, + result.expiresOn!.getTime() + ); + assert.equal(result.leaseDuration, "fixed"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + assert.equal(result.cacheControl, httpHeader.cacheControl); + assert.equal(result.contentEncoding, httpHeader.contentEncoding); + assert.equal(result.contentLanguage, httpHeader.contentLanguage); + assert.equal(result.contentDisposition, httpHeader.contentDisposition); + assert.equal(result.contentType, httpHeader.contentType); + const aclResult = await testFileClient.getAccessControl(); + const permissions = { + owner: { + read: true, + write: true, + execute: true + }, + group: { + read: false, + write: true, + execute: false + }, + other: { + read: false, + write: false, + execute: false + }, + stickyBit: false, + extendedAcls: false + }; + assert.deepEqual(aclResult.permissions, permissions); + }); + + it("DataLakeFileClient createIfNotExists with default parameters @loki @sql", async () => { + const testFileName = getUniqueName("testfile"); + const testFileClient = fileSystemClient.getFileClient(testFileName); + + await testFileClient.createIfNotExists(); + assert.ok(await testFileClient.exists()); + }); + + it("DataLakeFileClient createIfNotExists with meta data @loki @sql", async () => { + const testFileName = getUniqueName("testfile"); + const testFileClient = fileSystemClient.getFileClient(testFileName); + const metadata = { + a: "a", + b: "b" + }; + + await testFileClient.createIfNotExists({ metadata: metadata }); + const result = await testFileClient.getProperties(); + assert.deepStrictEqual(result.metadata, metadata); + }); + + it("DataLakeFileClient createIfNotExists with permission and umark @loki @sql", async () => { + const testFileName = getUniqueName("testfile"); + const testFileClient = fileSystemClient.getFileClient(testFileName); + const permissionString = "0777"; + const umask = "0057"; + + await testFileClient.createIfNotExists({ + permissions: permissionString, + umask: umask + }); + const result = await testFileClient.getAccessControl(); + const permissions = { + owner: { + read: true, + write: true, + execute: true + }, + group: { + read: false, + write: true, + execute: false + }, + other: { + read: false, + write: false, + execute: false + }, + stickyBit: false, + extendedAcls: false + }; + assert.deepEqual(result.permissions, permissions); + }); + + it("DataLakeFileClient createIfNotExists with headers @loki @sql", async () => { + const testFileName = getUniqueName("testfile"); + const testFileClient = fileSystemClient.getFileClient(testFileName); + const httpHeader = { + cacheControl: "control", + contentEncoding: "encoding", + contentLanguage: "language", + contentDisposition: "disposition", + contentType: "type/subtype" + }; + + await testFileClient.createIfNotExists({ pathHttpHeaders: httpHeader }); + const result = await testFileClient.getProperties(); + assert.equal(result.cacheControl, httpHeader.cacheControl); + assert.equal(result.contentEncoding, httpHeader.contentEncoding); + assert.equal(result.contentLanguage, httpHeader.contentLanguage); + assert.equal(result.contentDisposition, httpHeader.contentDisposition); + assert.equal(result.contentType, httpHeader.contentType); + }); + + it("DataLakeFileClient createIfNotExists with leaseId @loki @sql", async () => { + const testFileName = getUniqueName("testfile"); + const testFileClient = fileSystemClient.getFileClient(testFileName); + const leaseId = "25180729-00c9-42b0-938b-ecabce67a007"; + const leaseDuration = 20; + + await testFileClient.createIfNotExists({ + proposedLeaseId: leaseId, + leaseDuration: leaseDuration + }); + const result = await testFileClient.getProperties(); + assert.equal(result.leaseDuration, "fixed"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + }); + + it("DataLakeFileClient createIfNotExists with relative expiry @loki @sql", async () => { + const testFileName = getUniqueName("testfile"); + const testFileClient = fileSystemClient.getFileClient(testFileName); + const timeToExpireInMs = 60 * 60 * 1000; // 1hour + await testFileClient.createIfNotExists({ expiresOn: timeToExpireInMs }); + const result = await testFileClient.getProperties(); + assert.equal( + result.createdOn!.getTime() + 1000 * 3600, + result.expiresOn!.getTime() + ); + }); + + it.skip("DataLakeFileClient createIfNotExists with absolute expiry @loki @sql", async () => { + const now = new Date(); + const delta = 2 * 1000; + const expiresOn = new Date(now.getTime() + delta); + + const testFileName = getUniqueName("testfile"); + const testFileClient = fileSystemClient.getFileClient(testFileName); + await testFileClient.createIfNotExists({ expiresOn: expiresOn }); + + const result = await testFileClient.getProperties(); + const recordedExpiresOn = new Date(expiresOn.getTime()); + recordedExpiresOn.setMilliseconds(0); // milliseconds dropped + assert.equal(result.expiresOn?.getTime(), recordedExpiresOn.getTime()); + + await delay(delta); + assert.ok(!(await testFileClient.exists())); + }); + + it("DataLakeDirectoryClient create with default parameters @loki @sql", async () => { + const testDirName = getUniqueName("testdir"); + const testdirClient = fileSystemClient.getDirectoryClient(testDirName); + await testdirClient.create(); + assert.ok(await testdirClient.exists()); + }); + + it("DataLakeDirectoryClient create with meta data @loki @sql", async () => { + const testDirName = getUniqueName("testdir"); + const testDirClient = fileSystemClient.getDirectoryClient(testDirName); + const metadata = { + a: "a", + b: "b" + }; + + await testDirClient.create({ metadata: metadata }); + const result = await testDirClient.getProperties(); + assert.deepStrictEqual(result.metadata, { + ...metadata, + hdi_isfolder: "true" + }); + }); + + it("DataLakeDirectoryClient create with permission and umark @loki @sql", async () => { + const testDirName = getUniqueName("testdir"); + const testDirClient = fileSystemClient.getDirectoryClient(testDirName); + const permissionString = "0777"; + const umask = "0057"; + + await testDirClient.create({ permissions: permissionString, umask: umask }); + const result = await testDirClient.getAccessControl(); + const permissions = { + owner: { + read: true, + write: true, + execute: true + }, + group: { + read: false, + write: true, + execute: false + }, + other: { + read: false, + write: false, + execute: false + }, + stickyBit: false, + extendedAcls: false + }; + assert.deepEqual(result.permissions, permissions); + }); + + it("DataLakeDirectoryClient create with headers @loki @sql", async () => { + const testDirName = getUniqueName("testdir"); + const testDirClient = fileSystemClient.getDirectoryClient(testDirName); + const httpHeader = { + cacheControl: "control", + contentEncoding: "encoding", + contentLanguage: "language", + contentDisposition: "disposition", + contentType: "type/subtype" + }; + + await testDirClient.create({ pathHttpHeaders: httpHeader }); + const result = await testDirClient.getProperties(); + assert.equal(result.cacheControl, httpHeader.cacheControl); + assert.equal(result.contentEncoding, httpHeader.contentEncoding); + assert.equal(result.contentLanguage, httpHeader.contentLanguage); + assert.equal(result.contentDisposition, httpHeader.contentDisposition); + assert.equal(result.contentType, httpHeader.contentType); + }); + + it("DataLakeDirectoryClient create with leaseId @loki @sql", async () => { + const testDirName = getUniqueName("testdir"); + const testDirClient = fileSystemClient.getDirectoryClient(testDirName); + const leaseId = "25180729-00c9-42b0-938b-ecabce67a007"; + const leaseDuration = 20; + + await testDirClient.create({ + proposedLeaseId: leaseId, + leaseDuration: leaseDuration + }); + const result = await testDirClient.getProperties(); + assert.equal(result.leaseDuration, "fixed"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + }); + + it("DataLakeDirectoryClient create with all parameters @loki @sql", async () => { + const metadata = { + a: "a", + b: "b" + }; + + const permissionString = "0777"; + const umask = "0057"; + + const httpHeader = { + cacheControl: "control", + contentEncoding: "encoding", + contentLanguage: "language", + contentDisposition: "disposition", + contentType: "type/subtype" + }; + const leaseId = "25180729-00c9-42b0-938b-ecabce67a007"; + const leaseDuration = 20; + + const testDirName = getUniqueName("testdir"); + const testDirClient = fileSystemClient.getFileClient(testDirName); + await testDirClient.create({ + metadata: metadata, + permissions: permissionString, + umask: umask, + pathHttpHeaders: httpHeader, + proposedLeaseId: leaseId, + leaseDuration: leaseDuration + }); + + const result = await testDirClient.getProperties(); + assert.deepStrictEqual(result.metadata, metadata); + assert.equal(result.leaseDuration, "fixed"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + assert.equal(result.cacheControl, httpHeader.cacheControl); + assert.equal(result.contentEncoding, httpHeader.contentEncoding); + assert.equal(result.contentLanguage, httpHeader.contentLanguage); + assert.equal(result.contentDisposition, httpHeader.contentDisposition); + assert.equal(result.contentType, httpHeader.contentType); + const aclResult = await testDirClient.getAccessControl(); + const permissions = { + owner: { + read: true, + write: true, + execute: true + }, + group: { + read: false, + write: true, + execute: false + }, + other: { + read: false, + write: false, + execute: false + }, + stickyBit: false, + extendedAcls: false + }; + assert.deepEqual(aclResult.permissions, permissions); + }); + + it("DataLakeDirectoryClient create with relative expiry @loki @sql", async () => { + const testDirName = getUniqueName("testdir"); + const testDirClient = fileSystemClient.getDirectoryClient(testDirName); + const timeToExpireInMs = 60 * 60 * 1000; // 1hour + try { + await testDirClient.create({ expiresOn: timeToExpireInMs }); + assert.fail("Creating directory with expiry should fail."); + } catch (error) { + assert.ok( + (error as any).message.includes( + "Set Expiry is not supported for a directory" + ) + ); + } + }); + + it("DataLakeDirectoryClient create with absolute expiry @loki @sql", async () => { + const now = new Date(); + const delta = 20 * 1000; + const expiresOn = new Date(now.getTime() + delta); + + const testDirName = getUniqueName("testdir"); + const testDirClient = fileSystemClient.getDirectoryClient(testDirName); + + try { + await testDirClient.create({ expiresOn }); + assert.fail("Creating directory with expiry should fail."); + } catch (error) { + assert.ok( + (error as any).message.includes( + "Set Expiry is not supported for a directory" + ) + ); + } + }); + + it("DataLakeDirectoryClient createIfNotExists with default parameters @loki @sql", async () => { + const testDirName = getUniqueName("testdir"); + const testdirClient = fileSystemClient.getDirectoryClient(testDirName); + await testdirClient.createIfNotExists(); + assert.ok(await testdirClient.exists()); + }); + + it("DataLakeDirectoryClient createIfNotExists with meta data @loki @sql", async () => { + const testDirName = getUniqueName("testdir"); + const testDirClient = fileSystemClient.getDirectoryClient(testDirName); + const metadata = { + a: "a", + b: "b" + }; + + await testDirClient.createIfNotExists({ metadata: metadata }); + const result = await testDirClient.getProperties(); + assert.deepStrictEqual(result.metadata, { + ...metadata, + hdi_isfolder: "true" + }); + }); + + it("DataLakeDirectoryClient createIfNotExists with permission and umark @loki @sql", async () => { + const testDirName = getUniqueName("testdir"); + const testDirClient = fileSystemClient.getDirectoryClient(testDirName); + const permissionString = "0777"; + const umask = "0057"; + + await testDirClient.createIfNotExists({ + permissions: permissionString, + umask: umask + }); + const result = await testDirClient.getAccessControl(); + const permissions = { + owner: { + read: true, + write: true, + execute: true + }, + group: { + read: false, + write: true, + execute: false + }, + other: { + read: false, + write: false, + execute: false + }, + stickyBit: false, + extendedAcls: false + }; + assert.deepEqual(result.permissions, permissions); + }); + + it("DataLakeDirectoryClient createIfNotExists with headers @loki @sql", async () => { + const testDirName = getUniqueName("testdir"); + const testDirClient = fileSystemClient.getDirectoryClient(testDirName); + const httpHeader = { + cacheControl: "control", + contentEncoding: "encoding", + contentLanguage: "language", + contentDisposition: "disposition", + contentType: "type/subtype" + }; + + await testDirClient.createIfNotExists({ pathHttpHeaders: httpHeader }); + const result = await testDirClient.getProperties(); + assert.equal(result.cacheControl, httpHeader.cacheControl); + assert.equal(result.contentEncoding, httpHeader.contentEncoding); + assert.equal(result.contentLanguage, httpHeader.contentLanguage); + assert.equal(result.contentDisposition, httpHeader.contentDisposition); + assert.equal(result.contentType, httpHeader.contentType); + }); + + it("DataLakeDirectoryClient createIfNotExists with leaseId @loki @sql", async () => { + const testDirName = getUniqueName("testdir"); + const testDirClient = fileSystemClient.getDirectoryClient(testDirName); + const leaseId = "25180729-00c9-42b0-938b-ecabce67a007"; + const leaseDuration = 20; + + await testDirClient.createIfNotExists({ + proposedLeaseId: leaseId, + leaseDuration: leaseDuration + }); + const result = await testDirClient.getProperties(); + assert.equal(result.leaseDuration, "fixed"); + assert.equal(result.leaseState, "leased"); + assert.equal(result.leaseStatus, "locked"); + }); + + it("DataLakeDirectoryClient createIfNotExists with relative expiry @loki @sql", async () => { + const testDirName = getUniqueName("testdir"); + const testDirClient = fileSystemClient.getDirectoryClient(testDirName); + const timeToExpireInMs = 60 * 60 * 1000; // 1hour + try { + await testDirClient.createIfNotExists({ expiresOn: timeToExpireInMs }); + assert.fail("Creating directory with expiry should fail."); + } catch (error) { + assert.ok( + (error as any).message.includes( + "Set Expiry is not supported for a directory" + ) + ); + } + }); + + it("DataLakeDirectoryClient createIfNotExists with absolute expiry @loki @sql", async () => { + const now = new Date(); + const delta = 20 * 1000; + const expiresOn = new Date(now.getTime() + delta); + + const testDirName = getUniqueName("testdir"); + const testDirClient = fileSystemClient.getDirectoryClient(testDirName); + + try { + await testDirClient.createIfNotExists({ expiresOn: expiresOn }); + assert.fail("Creating directory with expiry should fail."); + } catch (error) { + assert.ok( + (error as any).message.includes( + "Set Expiry is not supported for a directory" + ) + ); + } + }); + + it("read with with default parameters @loki @sql", async () => { + const result = await fileClient.read(); + const read = await bodyToString(result, content.length); + assert.deepStrictEqual(read, content); + }); + + it("read should not have aborted error after read finishes @loki @sql", async () => { + const aborter = new AbortController(); + const result = await fileClient.read(0, undefined, { + abortSignal: aborter.signal + }); + const read = await bodyToString(result, content.length); + assert.deepStrictEqual(read, content); + aborter.abort(); + }); + + it("read all parameters set @loki @sql", async () => { + // For browser scenario, please ensure CORS settings exposed headers: content-md5,x-ms-content-crc64 + // So JS can get contentCrc64 and contentMD5. + const result1 = await fileClient.read(0, 1, { + rangeGetContentCrc64: true + }); + assert.ok(result1.clientRequestId); + // assert.ok(result1.contentCrc64!); + assert.deepStrictEqual(await bodyToString(result1, 1), content[0]); + assert.ok(result1.clientRequestId); + + const result2 = await fileClient.read(1, 1, { + rangeGetContentMD5: true + }); + assert.ok(result2.clientRequestId); + assert.ok(result2.contentMD5!); + + let exceptionCaught = false; + try { + await fileClient.read(2, 1, { + rangeGetContentMD5: true, + rangeGetContentCrc64: true + }); + } catch (err: any) { + exceptionCaught = true; + } + assert.ok(exceptionCaught); + }); + + it("setMetadata with new metadata set @loki @sql", async () => { + const metadata = { + a: "a", + b: "b" + }; + await fileClient.setMetadata(metadata); + const result = await fileClient.getProperties(); + assert.deepStrictEqual(result.metadata, metadata); + }); + + it("setMetadata with cleaning up metadata @loki @sql", async () => { + const metadata = { + a: "a", + b: "b" + }; + await fileClient.setMetadata(metadata); + const result = await fileClient.getProperties(); + assert.deepStrictEqual(result.metadata, metadata); + + await fileClient.setMetadata(); + const result2 = await fileClient.getProperties(); + assert.deepStrictEqual(result2.metadata, {}); + }); + + it("setHttpHeaders with default parameters @loki @sql", async () => { + await fileClient.setHttpHeaders({}); + const result = await fileClient.getProperties(); + + assert.ok(result.lastModified); + assert.deepStrictEqual(result.metadata, {}); + assert.ok(!result.cacheControl); + assert.ok(!result.contentType); + assert.ok(!result.contentMD5); + assert.ok(!result.contentEncoding); + assert.ok(!result.contentLanguage); + assert.ok(!result.contentDisposition); + }); + + it("setHttpHeaders with all parameters set @loki @sql", async () => { + const headers = { + cacheControl: "cacheControl", + contentDisposition: "contentDisposition", + contentEncoding: "contentEncoding", + contentLanguage: "contentLanguage", + contentMD5: new Uint8Array([1, 2, 3, 4]), + contentType: "contentType" + }; + await fileClient.setHttpHeaders(headers); + const result = await fileClient.getProperties(); + assert.ok(result.date); + + assert.ok(result.lastModified); + assert.deepStrictEqual(result.metadata, {}); + assert.deepStrictEqual(result.cacheControl, headers.cacheControl); + assert.deepStrictEqual(result.contentType, headers.contentType); + assert.deepStrictEqual( + Buffer.from(result.contentMD5!, 0), + Buffer.from(headers.contentMD5, 0) + ); + assert.deepStrictEqual(result.contentEncoding, headers.contentEncoding); + assert.deepStrictEqual(result.contentLanguage, headers.contentLanguage); + assert.deepStrictEqual( + result.contentDisposition, + headers.contentDisposition + ); + }); + + it("delete @loki @sql", async () => { + await fileClient.delete(); + }); + + it("read with default parameters and tracing @loki @sql", async () => { + const result = await fileClient.read(undefined, undefined); + assert.deepStrictEqual(await bodyToString(result, content.length), content); + }); + + it("verify fileName and fileSystemName passed to the client @loki @sql", async () => { + const accountName = "myaccount"; + const path = "file/part/1.txt"; + const newClient = new DataLakeFileClient( + `https://${accountName}.dfs.core.windows.net/` + + fileSystemName + + "/" + + path + ); + assert.equal( + newClient.fileSystemName, + fileSystemName, + "File system name is not the same as the one provided." + ); + assert.equal( + newClient.name, + path, + "File name is not the same as the one provided." + ); + assert.equal( + newClient.accountName, + accountName, + "Account name is not the same as the one provided." + ); + }); + + it("append with acquire lease @loki @sql", async () => { + const body = "HelloWorld"; + + const tempFileName = getUniqueName("tempfile2"); + const tempFileClient = fileSystemClient.getFileClient(tempFileName); + const leaseId = "ca761232ed4211cebacd00aa0057b223"; + + await tempFileClient.create(); + + await tempFileClient.append(body, 0, body.length, { + proposedLeaseId: leaseId, + leaseDurationInSeconds: 15, + leaseAction: "acquire" + }); + + let gotError = false; + try { + await tempFileClient.append(body, body.length, body.length, { + flush: true + }); + } catch (err) { + gotError = true; + assert.ok( + err.message.startsWith( + "There is currently a lease on the resource and no lease ID was specified in the request." + ) + ); + } + assert.ok( + gotError, + "Should throw out an exception to write to a leased file without lease id" + ); + + await tempFileClient.append(body, body.length, body.length, { + conditions: { + leaseId: leaseId + }, + flush: true + }); + + const properties = await tempFileClient.getProperties(); + assert.equal(properties.contentLength, body.length * 2); + assert.equal(properties.leaseState, "leased"); + assert.equal(properties.leaseDuration, "fixed"); + assert.equal(properties.leaseStatus, "locked"); + + await tempFileClient.delete(false, { + conditions: { + leaseId: leaseId + } + }); + }); + + it("append with auto-renew lease @loki @sql", async () => { + const body = "HelloWorld"; + + const tempFileName = getUniqueName("tempfile2"); + const tempFileClient = fileSystemClient.getFileClient(tempFileName); + const leaseId = "ca761232ed4211cebacd00aa0057b223"; + + await tempFileClient.create({ + proposedLeaseId: leaseId, + leaseDuration: 15 + }); + + const properties = await tempFileClient.getProperties(); + assert.equal(properties.leaseState, "leased"); + assert.equal(properties.leaseDuration, "fixed"); + assert.equal(properties.leaseStatus, "locked"); + + await sleep(15); + + await tempFileClient.append(body, 0, body.length, { + conditions: { leaseId: leaseId }, + leaseDurationInSeconds: 15, + leaseAction: "auto-renew" + }); + + let gotError = false; + try { + await tempFileClient.append(body, body.length, body.length, { + flush: true + }); + } catch (err) { + gotError = true; + assert.ok( + err.message.startsWith( + "There is currently a lease on the resource and no lease ID was specified in the request." + ) + ); + } + assert.ok( + gotError, + "Should throw out an exception to write to a leased file without lease id" + ); + + await tempFileClient.delete(false, { + conditions: { + leaseId: leaseId + } + }); + }); + + it("append with release lease @loki @sql", async () => { + const body = "HelloWorld"; + + const tempFileName = getUniqueName("tempfile2"); + const tempFileClient = fileSystemClient.getFileClient(tempFileName); + const leaseId = "ca761232ed4211cebacd00aa0057b223"; + + await tempFileClient.create({ + proposedLeaseId: leaseId, + leaseDuration: 15 + }); + + await tempFileClient.append(body, 0, body.length, { + conditions: { leaseId: leaseId } + }); + + await tempFileClient.append(body, body.length, body.length, { + conditions: { leaseId: leaseId }, + leaseAction: "release", + flush: true + }); + + const properties = await tempFileClient.getProperties(); + assert.equal(properties.leaseState, "available"); + assert.equal(properties.leaseStatus, "unlocked"); + + await tempFileClient.delete(); + }); + + it("flush with acquire lease @loki @sql", async () => { + const body = "HelloWorld"; + + const tempFileName = getUniqueName("tempfile2"); + const tempFileClient = fileSystemClient.getFileClient(tempFileName); + const leaseId = "ca761232ed4211cebacd00aa0057b223"; + + await tempFileClient.create(); + + await tempFileClient.append(body, 0, body.length); + await tempFileClient.append(body, body.length, body.length); + + await tempFileClient.flush(body.length * 2, { + proposedLeaseId: leaseId, + leaseDurationInSeconds: 15, + leaseAction: "acquire" + }); + + let gotError = false; + try { + await tempFileClient.delete(); + } catch (err) { + gotError = true; + assert.ok( + err.message.startsWith( + "There is currently a lease on the resource and no lease ID was specified in the request." + ) + ); + } + assert.ok( + gotError, + "Should throw out an exception to write to a leased file without lease id" + ); + + const properties = await tempFileClient.getProperties(); + assert.equal(properties.contentLength, body.length * 2); + assert.equal(properties.leaseState, "leased"); + assert.equal(properties.leaseDuration, "fixed"); + assert.equal(properties.leaseStatus, "locked"); + + await tempFileClient.delete(false, { + conditions: { + leaseId: leaseId + } + }); + }); + + it("flush with auto-renew lease @loki @sql", async () => { + const body = "HelloWorld"; + + const tempFileName = getUniqueName("tempfile2"); + const tempFileClient = fileSystemClient.getFileClient(tempFileName); + const leaseId = "ca761232ed4211cebacd00aa0057b223"; + + await tempFileClient.create({ + proposedLeaseId: leaseId, + leaseDuration: 15 + }); + + await tempFileClient.append(body, 0, body.length, { + conditions: { leaseId: leaseId } + }); + await tempFileClient.append(body, body.length, body.length, { + conditions: { leaseId: leaseId } + }); + + await sleep(15); + + await tempFileClient.flush(body.length * 2, { + conditions: { leaseId: leaseId }, + leaseDurationInSeconds: 15, + leaseAction: "auto-renew" + }); + + let gotError = false; + try { + await tempFileClient.delete(); + } catch (err) { + gotError = true; + assert.ok( + err.message.startsWith( + "There is currently a lease on the resource and no lease ID was specified in the request." + ) + ); + } + assert.ok( + gotError, + "Should throw out an exception to write to a leased file without lease id" + ); + + const properties = await tempFileClient.getProperties(); + assert.equal(properties.contentLength, body.length * 2); + assert.equal(properties.leaseState, "leased"); + assert.equal(properties.leaseDuration, "fixed"); + assert.equal(properties.leaseStatus, "locked"); + + await tempFileClient.delete(false, { + conditions: { + leaseId: leaseId + } + }); + }); + + it("flush with release lease @loki @sql", async () => { + const body = "HelloWorld"; + + const tempFileName = getUniqueName("tempfile2"); + const tempFileClient = fileSystemClient.getFileClient(tempFileName); + const leaseId = "ca761232ed4211cebacd00aa0057b223"; + + await tempFileClient.create({ + proposedLeaseId: leaseId, + leaseDuration: 15 + }); + + await tempFileClient.append(body, 0, body.length, { + conditions: { leaseId: leaseId } + }); + await tempFileClient.append(body, body.length, body.length, { + conditions: { leaseId: leaseId } + }); + + await tempFileClient.flush(body.length * 2, { + conditions: { leaseId: leaseId }, + leaseAction: "release" + }); + + const properties = await tempFileClient.getProperties(); + assert.equal(properties.leaseState, "available"); + assert.equal(properties.leaseStatus, "unlocked"); + + await tempFileClient.delete(); + }); + + it("append with flush should work @loki @sql", async () => { + const body = "HelloWorld"; + + const tempFileName = getUniqueName("tempfile2"); + const tempFileClient = fileSystemClient.getFileClient(tempFileName); + + await tempFileClient.create(); + + await tempFileClient.append(body, 0, body.length, { + transactionalContentMD5: new Uint8Array([]) + }); + await tempFileClient.append(body, body.length, body.length, { + transactionalContentMD5: new Uint8Array([]) + }); + await tempFileClient.append(body, body.length * 2, body.length, { + transactionalContentMD5: new Uint8Array([]), + flush: true + }); + + const properties = await tempFileClient.getProperties(); + assert.deepStrictEqual(properties.contentLength, body.length * 3); + + await tempFileClient.delete(); + }); + + it("append & flush should work @loki @sql", async () => { + const body = "HelloWorld"; + + const tempFileName = getUniqueName("tempfile2"); + const tempFileClient = fileSystemClient.getFileClient(tempFileName); + + await tempFileClient.create(); + + await tempFileClient.append(body, 0, body.length, { + transactionalContentMD5: new Uint8Array([]) + }); + await tempFileClient.append(body, body.length, body.length, { + transactionalContentMD5: new Uint8Array([]) + }); + await tempFileClient.append(body, body.length * 2, body.length, { + transactionalContentMD5: new Uint8Array([]) + }); + + await tempFileClient.flush(body.length * 3); + + const properties = await tempFileClient.getProperties(); + assert.deepStrictEqual(properties.contentLength, body.length * 3); + + await tempFileClient.delete(); + }); + + it("append & flush should work with all parameters @loki @sql", async () => { + const body = "HelloWorld"; + + const tempFileName = getUniqueName("tempfile2"); + const tempFileClient = fileSystemClient.getFileClient(tempFileName); + + const permissions = { + owner: { read: false, write: false, execute: false }, + group: { read: false, write: false, execute: false }, + other: { read: false, write: false, execute: false }, + stickyBit: false, + extendedAcls: false + }; + const permissionsString = toPermissionsString(permissions); + const metadata = { + a: "val-a", + b: "val-b" + }; + let pathHttpHeaders = { + cacheControl: "cacheControl", + contentEncoding: "contentEncoding", + contentLanguage: "contentLanguage", + contentDisposition: "contentDisposition", + contentType: "contentType" + }; + await tempFileClient.create({ + permissions: permissionsString, + metadata, + umask: "0000", + pathHttpHeaders + }); + + let properties = await tempFileClient.getProperties(); + assert.deepStrictEqual(properties.contentLength, 0); + assert.deepStrictEqual( + properties.cacheControl, + pathHttpHeaders.cacheControl + ); + assert.deepStrictEqual( + properties.contentEncoding, + pathHttpHeaders.contentEncoding + ); + assert.deepStrictEqual( + properties.contentLanguage, + pathHttpHeaders.contentLanguage + ); + assert.deepStrictEqual( + properties.contentDisposition, + pathHttpHeaders.contentDisposition + ); + assert.deepStrictEqual(properties.contentType, pathHttpHeaders.contentType); + assert.deepStrictEqual(properties.metadata, metadata); + + const acl = await tempFileClient.getAccessControl(); + assert.deepStrictEqual(acl.permissions, permissions); + + await tempFileClient.append(body, 0, body.length, { + transactionalContentMD5: new Uint8Array([]) + }); + await tempFileClient.append(body, body.length, body.length, { + transactionalContentMD5: new Uint8Array([]) + }); + await tempFileClient.append(body, body.length * 2, body.length, { + transactionalContentMD5: new Uint8Array([]) + }); + + pathHttpHeaders = { + cacheControl: "cacheControl2", + contentEncoding: "contentEncoding2", + contentLanguage: "contentLanguage2", + contentDisposition: "contentDisposition2", + contentType: "contentType2" + }; + await tempFileClient.flush(body.length * 3, { + retainUncommittedData: true, + close: true, + pathHttpHeaders + }); + + properties = await tempFileClient.getProperties(); + assert.deepStrictEqual(properties.contentLength, body.length * 3); + assert.deepStrictEqual( + properties.cacheControl, + pathHttpHeaders.cacheControl + ); + assert.deepStrictEqual( + properties.contentEncoding, + pathHttpHeaders.contentEncoding + ); + assert.deepStrictEqual( + properties.contentLanguage, + pathHttpHeaders.contentLanguage + ); + assert.deepStrictEqual( + properties.contentDisposition, + pathHttpHeaders.contentDisposition + ); + assert.deepStrictEqual(properties.contentType, pathHttpHeaders.contentType); + assert.deepStrictEqual(properties.metadata, metadata); + + await tempFileClient.delete(); + }); + + it("exists returns true on an existing file @loki @sql", async () => { + const result = await fileClient.exists(); + assert.ok(result, "exists() should return true for an existing file"); + }); + + it("exists returns false on non-existing file or directory @loki @sql", async () => { + const newFileClient = fileSystemClient.getFileClient( + getUniqueName("newFile") + ); + const result = await newFileClient.exists(); + assert.ok( + result === false, + "exists() should return false for a non-existing file" + ); + + const newDirectoryClient = fileSystemClient.getDirectoryClient( + getUniqueName("newDirectory") + ); + const dirResult = await newDirectoryClient.exists(); + assert.ok( + dirResult === false, + "exists() should return false for a non-existing directory" + ); + }); + + it("DataLakeDirectoryClient-createIfNotExists @loki @sql", async () => { + const directoryName = getUniqueName("dir"); + const directoryClient = fileSystemClient.getDirectoryClient(directoryName); + const res = await directoryClient.createIfNotExists(); + assert.ok(res.succeeded); + + const res2 = await directoryClient.createIfNotExists(); + assert.ok(!res2.succeeded); + assert.equal(res2.errorCode, "PathAlreadyExists"); + }); + + it("DataLakeFileClient-createIfNotExists @loki @sql", async () => { + const res = await fileClient.createIfNotExists(); + assert.ok(!res.succeeded); + assert.equal(res.errorCode, "PathAlreadyExists"); + }); + + it("DataLakePathClient-deleteIfExists @loki @sql", async () => { + const directoryName = getUniqueName("dir"); + const directoryClient = fileSystemClient.getDirectoryClient(directoryName); + const res = await directoryClient.deleteIfExists(); + assert.ok(!res.succeeded); + assert.equal(res.errorCode, "PathNotFound"); + + await directoryClient.create(); + const res2 = await directoryClient.deleteIfExists(); + assert.ok(res2.succeeded); + }); + + it("DataLakePathClient-deleteIfExists when parent not exists @loki @sql", async () => { + const directoryName = getUniqueName("dir"); + const directoryClient = fileSystemClient.getDirectoryClient(directoryName); + const newFileClient = directoryClient.getFileClient(fileName); + const res2 = await newFileClient.deleteIfExists(); + assert.ok(!res2.succeeded); + assert.deepStrictEqual(res2.errorCode, "PathNotFound"); + }); + + it.skip("set expiry - NeverExpire @loki @sql", async () => { + await fileClient.setExpiry("NeverExpire"); + const getRes = await fileClient.getProperties(); + assert.equal(getRes.expiresOn, undefined); + }); + + it.skip("set expiry - Absolute @loki @sql", async () => { + const now = new Date(); // Flaky workaround for the recording to work. + const delta = 5 * 1000; + const expiresOn = new Date(now.getTime() + delta); + await fileClient.setExpiry("Absolute", { expiresOn }); + + const getRes = await fileClient.getProperties(); + const recordedExpiresOn = new Date(expiresOn.getTime()); + recordedExpiresOn.setMilliseconds(0); // milliseconds dropped + assert.equal(getRes.expiresOn?.getTime(), recordedExpiresOn.getTime()); + + await delay(delta); + assert.ok(!(await fileClient.exists())); + }); + + it.skip("set expiry - RelativeToNow @loki @sql", async () => { + const delta = 1000; + await fileClient.setExpiry("RelativeToNow", { timeToExpireInMs: delta }); + + await delay(delta); + assert.ok(!(await fileClient.exists())); + }); + + it.skip("set expiry - RelativeToCreation @loki @sql", async () => { + const delta = 1000 * 3600 + 0.12; + await fileClient.setExpiry("RelativeToCreation", { + timeToExpireInMs: delta + }); + + const getRes = await fileClient.getProperties(); + assert.equal( + getRes.expiresOn?.getTime(), + getRes.createdOn!.getTime() + Math.round(delta) + ); + }); + + it.skip("set expiry - override @loki @sql", async () => { + const delta = 1000 * 3600; + await fileClient.setExpiry("RelativeToCreation", { + timeToExpireInMs: delta + }); + + const getRes = await fileClient.getProperties(); + assert.equal( + getRes.expiresOn?.getTime(), + getRes.createdOn!.getTime() + delta + ); + + await fileClient.setExpiry("NeverExpire"); + const getRes2 = await fileClient.getProperties(); + assert.equal(getRes2.expiresOn, undefined); + }); +}); + +describe.skip("DataLakePathClient with CPK", () => { + const factory = new BlobTestServerFactory(true); + const server = factory.createServer(); + + const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`; + const serviceClient = new DataLakeServiceClient( + baseURL, + new StorageSharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + + let fileSystemName: string; + let fileSystemClient: DataLakeFileSystemClient; + let fileName: string; + let dirName: string; + let fileClient: DataLakeFileClient; + let dirClient: DataLakeDirectoryClient; + const content = "Hello World"; + + before(async () => { + await server.start(); + }); + + after(async () => { + await server.close(); + await server.clean(); + }); + + beforeEach(async function () { + fileSystemName = getUniqueName("filesystem"); + fileSystemClient = serviceClient.getFileSystemClient(fileSystemName); + await fileSystemClient.createIfNotExists(); + fileName = getUniqueName("file"); + fileClient = fileSystemClient.getFileClient(fileName); + dirName = getUniqueName("dir"); + dirClient = fileSystemClient.getDirectoryClient(dirName); + }); + + afterEach(async function () { + await fileSystemClient.deleteIfExists(); + }); + + it("file create, append, flush and read with cpk @loki @sql", async () => { + await fileClient.create({ + customerProvidedKey: Test_CPK_INFO + }); + await fileClient.append(content, 0, content.length, { + customerProvidedKey: Test_CPK_INFO + }); + await fileClient.flush(content.length, { + customerProvidedKey: Test_CPK_INFO + }); + + const result = await fileClient.read(0, undefined, { + customerProvidedKey: Test_CPK_INFO + }); + assert.deepStrictEqual(await bodyToString(result, content.length), content); + }); + + it("file getProperties with CPK @loki @sql", async () => { + await fileClient.create({ + customerProvidedKey: Test_CPK_INFO + }); + + const result = await fileClient.getProperties({ + customerProvidedKey: Test_CPK_INFO + }); + + assert.equal(result.contentLength, 0); + }); + + it("file getProperties without CPK on a file with CPK @loki @sql", async () => { + await fileClient.create({ + customerProvidedKey: Test_CPK_INFO + }); + + let gotError = false; + try { + await fileClient.getProperties(); + } catch (err: any) { + gotError = true; + assert.equal((err as any).statusCode, 409); + } + + assert.ok(gotError, "Should got an error"); + }); + + it("file getProperties with CPK on a file without CPK @loki @sql", async () => { + await fileClient.create(); + + let gotError = false; + + try { + await fileClient.getProperties({ + customerProvidedKey: Test_CPK_INFO + }); + } catch (err: any) { + gotError = true; + assert.equal((err as any).statusCode, 409); + } + + assert.ok(gotError, "Should got an error"); + }); + + it("file exists with CPK @loki @sql", async () => { + await fileClient.create({ + customerProvidedKey: Test_CPK_INFO + }); + + assert.ok( + await fileClient.exists({ + customerProvidedKey: Test_CPK_INFO + }) + ); + }); + + it("file exists with CPK on a file without CPK @loki @sql", async () => { + await fileClient.create(); + + assert.ok( + await fileClient.exists({ + customerProvidedKey: Test_CPK_INFO + }) + ); + }); + + it("file exists without CPK on a file with CPK @loki @sql", async () => { + await fileClient.create({ + customerProvidedKey: Test_CPK_INFO + }); + + assert.ok(await fileClient.exists()); + }); + + it("file append with cpk to a file without CPK @loki @sql", async () => { + await fileClient.create(); + + let gotError = false; + + try { + await fileClient.append(content, 0, content.length, { + customerProvidedKey: Test_CPK_INFO + }); + } catch (err: any) { + gotError = true; + assert.equal((err as any).statusCode, 409); + } + + assert.ok(gotError, "Should got an error"); + }); + + it("file append without cpk to a file with CPK @loki @sql", async () => { + await fileClient.create({ + customerProvidedKey: Test_CPK_INFO + }); + + let gotError = false; + try { + await fileClient.append(content, 0, content.length); + } catch (err: any) { + gotError = true; + assert.equal((err as any).statusCode, 409); + } + + assert.ok(gotError, "Should got an error"); + }); + + it("file flush with cpk to a file without CPK @loki @sql", async () => { + await fileClient.create(); + await fileClient.append(content, 0, content.length); + + let gotError = false; + try { + await fileClient.flush(content.length, { + customerProvidedKey: Test_CPK_INFO + }); + } catch (err: any) { + gotError = true; + assert.equal((err as any).statusCode, 409); + } + assert.ok(gotError, "Should got an error"); + }); + + it("file flush without cpk to a file with CPK @loki @sql", async () => { + await fileClient.create({ + customerProvidedKey: Test_CPK_INFO + }); + await fileClient.append(content, 0, content.length, { + customerProvidedKey: Test_CPK_INFO + }); + + let gotError = false; + try { + await fileClient.flush(content.length); + } catch (err: any) { + gotError = true; + assert.equal((err as any).statusCode, 409); + } + assert.ok(gotError, "Should got an error"); + }); + + it("file read without cpk to a file with CPK @loki @sql", async () => { + await fileClient.create({ + customerProvidedKey: Test_CPK_INFO + }); + await fileClient.append(content, 0, content.length, { + customerProvidedKey: Test_CPK_INFO + }); + await fileClient.flush(content.length, { + customerProvidedKey: Test_CPK_INFO + }); + + let gotError = false; + try { + await fileClient.read(0, undefined); + } catch (err: any) { + gotError = true; + assert.equal((err as any).statusCode, 409); + } + assert.ok(gotError, "Should got an error"); + }); + + it("file read with cpk to a file without CPK @loki @sql", async () => { + await fileClient.create(); + await fileClient.append(content, 0, content.length); + await fileClient.flush(content.length); + + let gotError = false; + try { + await fileClient.read(0, undefined, { + customerProvidedKey: Test_CPK_INFO + }); + } catch (err: any) { + gotError = true; + assert.equal((err as any).statusCode, 409); + } + + assert.ok(gotError, "Should got an error"); + }); + + it("file setMetadata with CPK @loki @sql", async () => { + await fileClient.create({ + customerProvidedKey: Test_CPK_INFO + }); + + const metadata = { + a: "a", + b: "b" + }; + await fileClient.setMetadata(metadata, { + customerProvidedKey: Test_CPK_INFO + }); + const result = await fileClient.getProperties({ + customerProvidedKey: Test_CPK_INFO + }); + assert.deepStrictEqual(result.metadata, metadata); + }); + + it("file setMetadata without cpk to a file with CPK @loki @sql", async () => { + await fileClient.create({ + customerProvidedKey: Test_CPK_INFO + }); + + let gotError = false; + try { + await fileClient.setMetadata({}); + } catch (err: any) { + gotError = true; + assert.equal((err as any).statusCode, 409); + } + assert.ok(gotError, "Should got an error"); + }); + + it("file setMetadata with cpk to a file without CPK @loki @sql", async () => { + await fileClient.create(); + + let gotError = false; + try { + await fileClient.setMetadata( + {}, + { + customerProvidedKey: Test_CPK_INFO + } + ); + } catch (err: any) { + gotError = true; + assert.equal((err as any).statusCode, 409); + } + assert.ok(gotError, "Should got an error"); + }); + + it("directory create and getProperties with CPK @loki @sql", async () => { + await dirClient.create({ + customerProvidedKey: Test_CPK_INFO + }); + await dirClient.getProperties({ + customerProvidedKey: Test_CPK_INFO + }); + }); + + it("directory getProperties with CPK on a directory without CPK @loki @sql", async () => { + await dirClient.create(); + + let gotError = false; + try { + await dirClient.getProperties({ + customerProvidedKey: Test_CPK_INFO + }); + } catch (err: any) { + gotError = true; + assert.equal((err as any).statusCode, 409); + } + assert.ok(gotError, "Should got an error"); + }); + + it("directory getProperties without CPK on a directory with CPK @loki @sql", async () => { + await dirClient.create({ + customerProvidedKey: Test_CPK_INFO + }); + + let gotError = false; + try { + await dirClient.getProperties(); + } catch (err: any) { + gotError = true; + assert.equal((err as any).statusCode, 409); + } + assert.ok(gotError, "Should got an error"); + }); + + it("directory exists with CPK @loki @sql", async () => { + await dirClient.create({ + customerProvidedKey: Test_CPK_INFO + }); + assert.ok( + await dirClient.exists({ + customerProvidedKey: Test_CPK_INFO + }) + ); + }); + + it("directory exists with CPK on a directory without CPK @loki @sql", async () => { + await dirClient.create(); + assert.ok( + await dirClient.exists({ + customerProvidedKey: Test_CPK_INFO + }) + ); + }); + + it("directory exists without CPK on a directory with CPK @loki @sql", async () => { + await dirClient.create({ + customerProvidedKey: Test_CPK_INFO + }); + + assert.ok(await dirClient.exists()); + }); + + it("directory setMetadata with CPK @loki @sql", async () => { + await dirClient.create({ + customerProvidedKey: Test_CPK_INFO + }); + + const metadata = { + a: "a", + b: "b" + }; + await dirClient.setMetadata(metadata, { + customerProvidedKey: Test_CPK_INFO + }); + const result = await dirClient.getProperties({ + customerProvidedKey: Test_CPK_INFO + }); + assert.deepStrictEqual(result.metadata, { + ...metadata, + hdi_isfolder: "true" + }); + }); + + it("directory setMetadata without cpk to a directory with CPK @loki @sql", async () => { + await dirClient.create({ + customerProvidedKey: Test_CPK_INFO + }); + + let gotError = false; + try { + await dirClient.setMetadata({}); + } catch (err: any) { + gotError = true; + assert.equal((err as any).statusCode, 409); + } + assert.ok(gotError, "Should got an error"); + }); + + it("directory setMetadata with cpk to a directory without CPK @loki @sql", async () => { + await dirClient.create(); + + let gotError = false; + try { + await dirClient.setMetadata( + {}, + { + customerProvidedKey: Test_CPK_INFO + } + ); + } catch (err: any) { + gotError = true; + assert.equal((err as any).statusCode, 409); + } + assert.ok(gotError, "Should got an error"); + }); +}); + +describe.skip("DataLakePathClient - Encryption Scope", () => { + const factory = new BlobTestServerFactory(true); + const server = factory.createServer(); + + const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`; + const serviceClient = new DataLakeServiceClient( + baseURL, + new StorageSharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + + let fileSystemName: string; + let fileSystemClient: DataLakeFileSystemClient; + let encryptionScopeName: string; + + before(async () => { + await server.start(); + }); + + after(async () => { + await server.close(); + await server.clean(); + }); + + beforeEach(async function (this: Context) { + encryptionScopeName = getEncryptionScope(); + fileSystemName = getUniqueName("filesystem"); + fileSystemClient = serviceClient.getFileSystemClient(fileSystemName); + await fileSystemClient.createIfNotExists({ + fileSystemEncryptionScope: { + defaultEncryptionScope: encryptionScopeName, + preventEncryptionScopeOverride: true + } + }); + }); + + afterEach(async function () { + await fileSystemClient?.deleteIfExists(); + }); + + it("DataLakeFileClient - getProperties should return Encryption Scope @loki @sql", async () => { + const fileName = getUniqueName("file"); + const fileClient = fileSystemClient.getFileClient(fileName); + await fileClient.create(); + const result = await fileClient.getProperties(); + assert.equal(result.encryptionScope, encryptionScopeName); + }); + + it("DataLakeDirectoryClient - getProperties should return Encryption Scope @loki @sql", async () => { + const dirName = getUniqueName("dir"); + const dirClient = fileSystemClient.getDirectoryClient(dirName); + await dirClient.create(); + const result = await dirClient.getProperties(); + assert.equal(result.encryptionScope, encryptionScopeName); + }); +}); diff --git a/tests/dfs/apis/serviceclient.test.ts b/tests/dfs/apis/serviceclient.test.ts new file mode 100644 index 000000000..dd87510b4 --- /dev/null +++ b/tests/dfs/apis/serviceclient.test.ts @@ -0,0 +1,620 @@ +// Copyright (c) Microsoft Corporation. +import assert from "assert"; +import { Context } from "mocha"; + +import { delay } from "@azure/ms-rest-js"; +// Licensed under the MIT license. +import { + DataLakeServiceClient, + DataLakeServiceProperties, + FileSystemItem, + ServiceListFileSystemsSegmentResponse, + StorageSharedKeyCredential +} from "@azure/storage-file-datalake"; + +import { + EMULATOR_ACCOUNT_KEY, + EMULATOR_ACCOUNT_NAME, + getEncryptionScope, + getUniqueName, + getYieldedValue +} from "../../testutils"; +import BlobTestServerFactory from "../../BlobTestServerFactory"; + +describe("DataLakeServiceClient", () => { + const factory = new BlobTestServerFactory(true); + const server = factory.createServer(); + + const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`; + const serviceClient = new DataLakeServiceClient( + baseURL, + new StorageSharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + + before(async () => { + await server.start(); + }); + + after(async () => { + await server.close(); + await server.clean(); + }); + + beforeEach(async function (this: Context) { + shouldSkip(this); + }); + + it("SetProperties and GetProperties @loki @sql", async () => { + const previousProperties = await serviceClient.getProperties(); + + let serviceProperties: DataLakeServiceProperties; + + // Need to determine serviceProperties's type before assigning. + /* eslint-disable-next-line prefer-const */ + serviceProperties = { + blobAnalyticsLogging: { + deleteProperty: true, + read: true, + retentionPolicy: { + days: 5, + enabled: true + }, + version: "1.0", + write: true + }, + minuteMetrics: { + enabled: true, + includeAPIs: true, + retentionPolicy: { + days: 4, + enabled: true + }, + version: "1.0" + }, + hourMetrics: { + enabled: true, + includeAPIs: true, + retentionPolicy: { + days: 3, + enabled: true + }, + version: "1.0" + }, + deleteRetentionPolicy: { + days: 2, + enabled: true + } + }; + + await serviceClient.setProperties(serviceProperties); + await delay(5 * 1000); + + let properties = await serviceClient.getProperties(); + assert.deepStrictEqual( + serviceProperties.blobAnalyticsLogging, + properties.blobAnalyticsLogging + ); + assert.deepStrictEqual( + serviceProperties.hourMetrics, + properties.hourMetrics + ); + assert.deepStrictEqual( + serviceProperties.minuteMetrics, + properties.minuteMetrics + ); + assert.deepStrictEqual( + serviceProperties.deleteRetentionPolicy?.days, + properties.deleteRetentionPolicy?.days + ); + assert.deepStrictEqual( + serviceProperties.deleteRetentionPolicy?.enabled, + properties.deleteRetentionPolicy?.enabled + ); + + // Cleanup + await serviceClient.setProperties(previousProperties); + await delay(5 * 1000); + + properties = await serviceClient.getProperties(); + if (previousProperties.cors !== undefined) { + assert.deepStrictEqual(previousProperties.cors, properties.cors); + } + + if (previousProperties.blobAnalyticsLogging !== undefined) { + assert.deepStrictEqual( + previousProperties.blobAnalyticsLogging, + properties.blobAnalyticsLogging + ); + } + + if (previousProperties.hourMetrics !== undefined) { + assert.deepStrictEqual( + previousProperties.hourMetrics, + properties.hourMetrics + ); + } + + if (previousProperties.minuteMetrics !== undefined) { + assert.deepStrictEqual( + previousProperties.minuteMetrics, + properties.minuteMetrics + ); + } + + if (previousProperties.deleteRetentionPolicy?.days !== undefined) { + assert.deepStrictEqual( + previousProperties.deleteRetentionPolicy?.days, + properties.deleteRetentionPolicy?.days + ); + } + + if (previousProperties.deleteRetentionPolicy?.enabled !== undefined) { + assert.deepStrictEqual( + previousProperties.deleteRetentionPolicy?.enabled, + properties.deleteRetentionPolicy?.enabled + ); + } + }); + + it("ListFileSystems with default parameters @loki @sql", async () => { + const result = (await serviceClient.listFileSystems().byPage().next()) + .value as ServiceListFileSystemsSegmentResponse; + assert.ok(typeof result.requestId); + assert.ok(result.requestId!.length > 0); + assert.ok(typeof result.version); + assert.ok(result.version!.length > 0); + assert.ok(typeof result.clientRequestId); + assert.ok(result.clientRequestId!.length > 0); + + assert.ok(result.serviceEndpoint.length > 0); + assert.ok(result.fileSystemItems.length >= 0); + + if (result.fileSystemItems.length > 0) { + const filesystem = result.fileSystemItems[0]; + assert.ok(filesystem.name.length > 0); + assert.ok(filesystem.properties.etag.length > 0); + assert.ok(filesystem.properties.lastModified); + } + }); + + it("ListFileSystems - returns file system encryption scope info @loki @sql", async function (this: Context) { + let encryptionScopeName: string | undefined; + try { + encryptionScopeName = getEncryptionScope(); + } catch { + this.skip(); + } + + const fileSystemName = getUniqueName("filesystem"); + const cClient = serviceClient.getFileSystemClient(fileSystemName); + await cClient.create({ + fileSystemEncryptionScope: { + defaultEncryptionScope: encryptionScopeName, + preventEncryptionScopeOverride: true + } + }); + + const result = (await serviceClient.listFileSystems().byPage().next()) + .value; + assert.ok(result.fileSystemItems.length >= 0); + + let foundTheOne = false; + result.fileSystemItems.forEach((element: FileSystemItem) => { + if (element.name === fileSystemName) { + foundTheOne = true; + assert.equal( + element.properties.defaultEncryptionScope, + encryptionScopeName + ); + } + }); + + assert.ok(foundTheOne, "Should have found the created file system"); + await cClient.delete(); + }); + + it("ListFileSystems - PagedAsyncIterableIterator returns file system encryption scope info @loki @sql", async function (this: Context) { + let encryptionScopeName: string | undefined; + try { + encryptionScopeName = getEncryptionScope(); + } catch { + this.skip(); + } + + const fileSystemName = getUniqueName("filesystem"); + const cClient = serviceClient.getFileSystemClient(fileSystemName); + await cClient.create({ + fileSystemEncryptionScope: { + defaultEncryptionScope: encryptionScopeName, + preventEncryptionScopeOverride: true + } + }); + + let foundTheOne = false; + + for await (const filesystem of serviceClient.listFileSystems()) { + if (filesystem.name === fileSystemName) { + foundTheOne = true; + assert.equal( + filesystem.properties.defaultEncryptionScope, + encryptionScopeName + ); + } + } + + assert.ok(foundTheOne, "Should have found the created file system"); + await cClient.delete(); + }); + + it("ListFileSystems with default parameters - null prefix shouldn't throw error @loki @sql", async () => { + const result = ( + await serviceClient.listFileSystems({ prefix: "" }).byPage().next() + ).value; + + assert.ok(result.fileSystemItems.length >= 0); + + if (result.fileSystemItems.length > 0) { + const filesystem = result.fileSystemItems[0]; + assert.ok(filesystem.name.length > 0); + assert.ok(filesystem.properties.etag.length > 0); + assert.ok(filesystem.properties.lastModified); + } + }); + + it("ListFileSystems with all parameters configured @loki @sql", async function (this: Context) { + const fileSystemNamePrefix = getUniqueName("filesystem1"); + const fileSystemName1 = `${fileSystemNamePrefix}x1`; + const fileSystemName2 = `${fileSystemNamePrefix}x2`; + const fileSystemClient1 = + serviceClient.getFileSystemClient(fileSystemName1); + const fileSystemClient2 = + serviceClient.getFileSystemClient(fileSystemName2); + await fileSystemClient1.create({ metadata: { key: "val" } }); + await fileSystemClient2.create({ metadata: { key: "val" } }); + + const result1 = ( + await serviceClient + .listFileSystems({ + includeMetadata: true, + prefix: fileSystemNamePrefix + }) + .byPage({ maxPageSize: 1 }) + .next() + ).value as ServiceListFileSystemsSegmentResponse; // TODO: Why no intelligence? + + assert.ok(result1.continuationToken); + assert.equal(result1.fileSystemItems.length, 1); + assert.ok(result1.fileSystemItems[0].name.startsWith(fileSystemNamePrefix)); + assert.ok(result1.fileSystemItems[0].properties.etag.length > 0); + assert.ok(result1.fileSystemItems[0].properties.lastModified); + assert.ok(!result1.fileSystemItems[0].properties.leaseDuration); + assert.ok(!result1.fileSystemItems[0].properties.publicAccess); + assert.deepEqual( + result1.fileSystemItems[0].properties.leaseState, + "available" + ); + assert.deepEqual( + result1.fileSystemItems[0].properties.leaseStatus, + "unlocked" + ); + assert.deepEqual(result1.fileSystemItems[0].metadata!.key, "val"); + + const result2 = ( + await serviceClient + .listFileSystems({ + includeMetadata: true, + prefix: fileSystemNamePrefix + }) + .byPage({ + continuationToken: result1.continuationToken, + maxPageSize: 1 + }) + .next() + ).value as ServiceListFileSystemsSegmentResponse; + + assert.ok(!result2.continuationToken); + assert.equal(result2.fileSystemItems.length, 1); + assert.ok(result2.fileSystemItems[0].name.startsWith(fileSystemNamePrefix)); + assert.ok(result2.fileSystemItems[0].properties.etag.length > 0); + assert.ok(result2.fileSystemItems[0].properties.lastModified); + assert.ok(!result2.fileSystemItems[0].properties.leaseDuration); + assert.ok(!result2.fileSystemItems[0].properties.publicAccess); + assert.deepEqual( + result2.fileSystemItems[0].properties.leaseState, + "available" + ); + assert.deepEqual( + result2.fileSystemItems[0].properties.leaseStatus, + "unlocked" + ); + assert.deepEqual(result2.fileSystemItems[0].metadata!.key, "val"); + + await fileSystemClient1.deleteIfExists(); + await fileSystemClient2.deleteIfExists(); + }); + + it("Verify PagedAsyncIterableIterator for ListFileSystems @loki @sql", async () => { + const fileSystemClients = []; + const fileSystemNamePrefix = getUniqueName("filesystem2"); + + for (let i = 0; i < 4; i++) { + const fileSystemName = `${fileSystemNamePrefix}x${i}`; + const fileSystemClient = + serviceClient.getFileSystemClient(fileSystemName); + await fileSystemClient.create({ metadata: { key: "val" } }); + fileSystemClients.push(fileSystemClient); + } + + for await (const filesystem of serviceClient.listFileSystems({ + includeMetadata: true, + prefix: fileSystemNamePrefix + })) { + assert.ok(filesystem.name.startsWith(fileSystemNamePrefix)); + assert.ok(filesystem.properties.etag.length > 0); + assert.ok(filesystem.properties.lastModified); + assert.ok(!filesystem.properties.leaseDuration); + assert.ok(!filesystem.properties.publicAccess); + assert.deepEqual(filesystem.properties.leaseState, "available"); + assert.deepEqual(filesystem.properties.leaseStatus, "unlocked"); + assert.deepEqual(filesystem.metadata!.key, "val"); + } + + for (const client of fileSystemClients) { + await client.deleteIfExists(); + } + }); + + it("Verify PagedAsyncIterableIterator(generator .next() syntax) for ListFileSystems @loki @sql", async () => { + const fileSystemNamePrefix = getUniqueName("filesystem3"); + const fileSystemName1 = `${fileSystemNamePrefix}x1`; + const fileSystemName2 = `${fileSystemNamePrefix}x2`; + const fileSystemClient1 = + serviceClient.getFileSystemClient(fileSystemName1); + const fileSystemClient2 = + serviceClient.getFileSystemClient(fileSystemName2); + await fileSystemClient1.create({ metadata: { key: "val" } }); + await fileSystemClient2.create({ metadata: { key: "val" } }); + + const iterator = serviceClient.listFileSystems({ + includeMetadata: true, + prefix: fileSystemNamePrefix + }); + + let fileSystemItem = getYieldedValue(await iterator.next()); + assert.ok(fileSystemItem.name.startsWith(fileSystemNamePrefix)); + assert.ok(fileSystemItem.properties.etag.length > 0); + assert.ok(fileSystemItem.properties.lastModified); + assert.ok(!fileSystemItem.properties.leaseDuration); + assert.ok(!fileSystemItem.properties.publicAccess); + assert.deepEqual(fileSystemItem.properties.leaseState, "available"); + assert.deepEqual(fileSystemItem.properties.leaseStatus, "unlocked"); + assert.deepEqual(fileSystemItem.metadata!.key, "val"); + + fileSystemItem = getYieldedValue(await iterator.next()); + assert.ok(fileSystemItem.name.startsWith(fileSystemNamePrefix)); + assert.ok(fileSystemItem.properties.etag.length > 0); + assert.ok(fileSystemItem.properties.lastModified); + assert.ok(!fileSystemItem.properties.leaseDuration); + assert.ok(!fileSystemItem.properties.publicAccess); + assert.deepEqual(fileSystemItem.properties.leaseState, "available"); + assert.deepEqual(fileSystemItem.properties.leaseStatus, "unlocked"); + assert.deepEqual(fileSystemItem.metadata!.key, "val"); + + await fileSystemClient1.deleteIfExists(); + await fileSystemClient2.deleteIfExists(); + }); + + it("Verify PagedAsyncIterableIterator(byPage()) for ListFileSystems @loki @sql", async function (this: Context) { + const fileSystemClients = []; + const fileSystemNamePrefix = getUniqueName("filesystem4"); + + for (let i = 0; i < 4; i++) { + const fileSystemName = `${fileSystemNamePrefix}x${i}`; + const fileSystemClient = + serviceClient.getFileSystemClient(fileSystemName); + await fileSystemClient.create({ metadata: { key: "val" } }); + fileSystemClients.push(fileSystemClient); + } + + for await (const response of serviceClient + .listFileSystems({ + includeMetadata: true, + prefix: fileSystemNamePrefix + }) + .byPage({ maxPageSize: 2 })) { + for (const filesystem of response.fileSystemItems) { + assert.ok(filesystem.name.startsWith(fileSystemNamePrefix)); + assert.ok(filesystem.properties.etag.length > 0); + assert.ok(filesystem.properties.lastModified); + assert.ok(!filesystem.properties.leaseDuration); + assert.ok(!filesystem.properties.publicAccess); + assert.deepEqual(filesystem.properties.leaseState, "available"); + assert.deepEqual(filesystem.properties.leaseStatus, "unlocked"); + assert.deepEqual(filesystem.metadata!.key, "val"); + } + } + + for (const client of fileSystemClients) { + await client.deleteIfExists(); + } + }); + + it("Verify PagedAsyncIterableIterator(byPage() - continuationToken) for ListFileSystems @loki @sql", async function (this: Context) { + const fileSystemClients = []; + const fileSystemNamePrefix = getUniqueName("filesystem5"); + + for (let i = 0; i < 4; i++) { + const fileSystemName = `${fileSystemNamePrefix}x${i}`; + const fileSystemClient = + serviceClient.getFileSystemClient(fileSystemName); + await fileSystemClient.create({ metadata: { key: "val" } }); + fileSystemClients.push(fileSystemClient); + } + + let iter = serviceClient + .listFileSystems({ + includeMetadata: true, + prefix: fileSystemNamePrefix + }) + .byPage({ maxPageSize: 2 }); + let response = (await iter.next()).value; + for (const filesystem of response.fileSystemItems) { + assert.ok(filesystem.name.startsWith(fileSystemNamePrefix)); + assert.ok(filesystem.properties.etag.length > 0); + assert.ok(filesystem.properties.lastModified); + assert.ok(!filesystem.properties.leaseDuration); + assert.ok(!filesystem.properties.publicAccess); + assert.deepEqual(filesystem.properties.leaseState, "available"); + assert.deepEqual(filesystem.properties.leaseStatus, "unlocked"); + assert.deepEqual(filesystem.metadata!.key, "val"); + } + // Gets next marker + const marker = response.continuationToken; + // Passing next marker as continuationToken + iter = serviceClient + .listFileSystems({ + includeMetadata: true, + prefix: fileSystemNamePrefix + }) + .byPage({ continuationToken: marker, maxPageSize: 2 }); + response = (await iter.next()).value; + // Gets 2 containers + for (const filesystem of response.fileSystemItems) { + assert.ok(filesystem.name.startsWith(fileSystemNamePrefix)); + assert.ok(filesystem.properties.etag.length > 0); + assert.ok(filesystem.properties.lastModified); + assert.ok(!filesystem.properties.leaseDuration); + assert.ok(!filesystem.properties.publicAccess); + assert.deepEqual(filesystem.properties.leaseState, "available"); + assert.deepEqual(filesystem.properties.leaseStatus, "unlocked"); + assert.deepEqual(filesystem.metadata!.key, "val"); + } + + for (const client of fileSystemClients) { + await client.deleteIfExists(); + } + }); + + it("createFileSystem and deleteFileSystem @loki @sql", async () => { + const fileSystemName = getUniqueName("filesystem6"); + const fileSystemClient = serviceClient.getFileSystemClient(fileSystemName); + const access = "filesystem"; + const metadata = { key: "value" }; + + await fileSystemClient.create({ + access, + metadata + }); + + const result = await fileSystemClient.getProperties(); + assert.deepEqual(result.publicAccess, access); + assert.deepEqual(result.metadata, metadata); + + await serviceClient.getFileSystemClient(fileSystemName).delete(); + try { + await fileSystemClient.getProperties(); + assert.fail( + "Expecting an error in getting properties from a deleted block blob but didn't get one." + ); + } catch (error) { + assert.ok((error.statusCode as number) === 404); + } + }); + + it("renameFileSystem should work @loki @sql", async function (this: Context) { + const fileSystemName = getUniqueName("filesystem"); + const fileSystemClient = serviceClient.getFileSystemClient(fileSystemName); + await fileSystemClient.create(); + + const newFileSystemName = getUniqueName("newfilesystem"); + // const renameRes = await serviceClient.renameFileSystem(fileSystemName, newFileSystemName); + const renameRes = await serviceClient["renameFileSystem"]( + fileSystemName, + newFileSystemName + ); + + const newFileSystemClient = + serviceClient.getFileSystemClient(newFileSystemName); + assert.deepStrictEqual(newFileSystemClient, renameRes.fileSystemClient); + await newFileSystemClient.getProperties(); + + await newFileSystemClient.delete(); + }); + + it("renameFileSystem should work with source lease @loki @sql", async function (this: Context) { + const fileSystemName = getUniqueName("filesystem"); + const fileSystemClient = serviceClient.getFileSystemClient(fileSystemName); + await fileSystemClient.create(); + + const leaseClient = fileSystemClient.getDataLakeLeaseClient(); + await leaseClient.acquireLease(-1); + + const newFileSystemName = getUniqueName("newfilesystem"); + // const renameRes = await serviceClient.renameFileSystem(fileSystemName, newFileSystemName, { + const renameRes = await serviceClient["renameFileSystem"]( + fileSystemName, + newFileSystemName, + { + sourceCondition: { leaseId: leaseClient.leaseId } + } + ); + + const newFileSystemClient = + serviceClient.getFileSystemClient(newFileSystemName); + assert.deepStrictEqual(newFileSystemClient, renameRes.fileSystemClient); + await newFileSystemClient.getProperties(); + + await newFileSystemClient.deleteIfExists(); + }); + + it("undelete and list deleted file system should work @loki @sql", async function (this: Context) { + const fileSystemName = getUniqueName("filesystem"); + const fileSystemClient = serviceClient.getFileSystemClient(fileSystemName); + await fileSystemClient.create(); + + const metadata = { a: "a" }; + await fileSystemClient.setMetadata(metadata); + + await fileSystemClient.delete(); + await delay(30 * 1000); + + let listed = false; + for await (const fileSystemItem of serviceClient.listFileSystems({ + includeDeleted: true, + includeMetadata: true + })) { + if (fileSystemItem.deleted && fileSystemItem.name === fileSystemName) { + listed = true; + // verify list container response + assert.ok(fileSystemItem.versionId); + assert.ok(fileSystemItem.deleted); + assert.ok(fileSystemItem.properties.deletedOn); + assert.ok(fileSystemItem.properties.remainingRetentionDays); + assert.deepStrictEqual(fileSystemItem.metadata, metadata); + + const restoreRes = await serviceClient.undeleteFileSystem( + fileSystemName, + fileSystemItem.versionId! + ); + assert.equal(restoreRes.fileSystemClient.name, fileSystemName); + await restoreRes.fileSystemClient.delete(); + break; + } + } + assert.ok(listed); + }); +}); + +function shouldSkip(context: Context) { + if ( + context.currentTest!.title.indexOf("undelete") > -1 || + context.currentTest!.title.indexOf("renameFileSystem") > -1 + ) { + context.skip(); + } +} diff --git a/tests/dfs/apis/specialnaming.test.ts b/tests/dfs/apis/specialnaming.test.ts new file mode 100644 index 000000000..3641d762e --- /dev/null +++ b/tests/dfs/apis/specialnaming.test.ts @@ -0,0 +1,349 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import assert from "assert"; +import { Context } from "mocha"; + +import { + DataLakeFileClient, + DataLakeFileSystemClient, + DataLakeServiceClient, + StorageSharedKeyCredential +} from "@azure/storage-file-datalake"; + +import { configLogger } from "../../../src/common/Logger"; +import { + appendToURLPath, + EMULATOR_ACCOUNT_KEY, + EMULATOR_ACCOUNT_NAME, + getUniqueName +} from "../../testutils"; +import BlobTestServerFactory from "../../BlobTestServerFactory"; + +// Set true to enable debug log +configLogger(false); + +describe("Special Naming Tests", () => { + const factory = new BlobTestServerFactory(true); + const server = factory.createServer(); + + const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`; + const serviceClient = new DataLakeServiceClient( + baseURL, + new StorageSharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + + let fileSystemName: string; + let fileSystemClient: DataLakeFileSystemClient; + + before(async () => { + await server.start(); + }); + + after(async () => { + await server.close(); + await server.clean(); + }); + + beforeEach(async function (this: Context) { + fileSystemName = getUniqueName("1container-with-dash"); + fileSystemClient = serviceClient.getFileSystemClient(fileSystemName); + await fileSystemClient.createIfNotExists(); + }); + + afterEach(async function () { + await fileSystemClient.deleteIfExists(); + }); + + it("Should work with special container and blob names with unicode @loki @sql", async () => { + const fileName: string = getUniqueName("unicod\u00e9"); + const fileClient = fileSystemClient.getFileClient(fileName); + + await fileClient.create(); + const response = (await fileSystemClient.listPaths().byPage().next()).value; + + assert.deepStrictEqual(response.pathItems.length, 1); + assert.deepStrictEqual(response.pathItems[0].name, fileName); + }); + + it("Should work with special container and blob names with unicode in URL string @loki @sql", async () => { + const fileName: string = getUniqueName("unicod\u00e9"); + const fileClient = new DataLakeFileClient( + appendToURLPath(fileSystemClient.url, fileName), + (fileSystemClient as any).pipeline + ); + + await fileClient.create(); + const response = (await fileSystemClient.listPaths().byPage().next()).value; + + assert.deepStrictEqual(response.pathItems.length, 1); + assert.deepStrictEqual(response.pathItems[0].name, fileName); + }); + + it("Should work with special container and blob names with spaces @loki @sql", async () => { + const fileName: string = getUniqueName("blob empty"); + const fileClient = fileSystemClient.getFileClient(fileName); + + await fileClient.create(); + const response = (await fileSystemClient.listPaths().byPage().next()).value; + + assert.deepStrictEqual(response.pathItems.length, 1); + assert.deepStrictEqual(response.pathItems[0].name, fileName); + }); + + it("Should work with special container and blob names with spaces in URL string @loki @sql", async () => { + const fileName: string = getUniqueName("blob empty"); + const fileClient = new DataLakeFileClient( + appendToURLPath(fileSystemClient.url, fileName), + (fileSystemClient as any).pipeline + ); + + await fileClient.create(); + const response = (await fileSystemClient.listPaths().byPage().next()).value; + + assert.deepStrictEqual(response.pathItems.length, 1); + assert.deepStrictEqual(response.pathItems[0].name, fileName); + }); + + /******************************************************************************************************* + * "/" test cases are Invalid in DataLake since "/" denotes folder structure so can only work encoded + * ********************************************************************************************************/ + + it("Should work with special container and blob names uppercase @loki @sql", async () => { + const fileName: string = getUniqueName("Upper blob empty another"); + const fileClient = fileSystemClient.getFileClient(fileName); + + await fileClient.create(); + await fileClient.getProperties(); + const response = (await fileSystemClient.listPaths({}).byPage().next()) + .value; + + assert.deepStrictEqual(response.pathItems.length, 1); + assert.deepStrictEqual(response.pathItems[0].name, fileName); + }); + + it("Should work with special container and blob names uppercase in URL string @loki @sql", async () => { + const fileName: string = getUniqueName("Upper blob empty another"); + const fileClient = new DataLakeFileClient( + appendToURLPath(fileSystemClient.url, fileName), + (fileSystemClient as any).pipeline + ); + + await fileClient.create(); + await fileClient.getProperties(); + const response = (await fileSystemClient.listPaths({}).byPage().next()) + .value; + + assert.deepStrictEqual(response.pathItems.length, 1); + assert.deepStrictEqual(response.pathItems[0].name, fileName); + }); + + it("Should work with special blob names Chinese characters @loki @sql", async () => { + const fileName: string = getUniqueName("Upper blob empty another 汉字"); + const fileClient = fileSystemClient.getFileClient(fileName); + + await fileClient.create(); + await fileClient.getProperties(); + const response = (await fileSystemClient.listPaths({}).byPage().next()) + .value; + + assert.deepStrictEqual(response.pathItems.length, 1); + assert.deepStrictEqual(response.pathItems[0].name, fileName); + }); + + it("Should work with special blob names Chinese characters in URL string @loki @sql", async () => { + const fileName: string = getUniqueName("Upper blob empty another 汉字"); + const fileClient = new DataLakeFileClient( + appendToURLPath(fileSystemClient.url, fileName), + (fileSystemClient as any).pipeline + ); + + await fileClient.create(); + await fileClient.getProperties(); + const response = (await fileSystemClient.listPaths({}).byPage().next()) + .value; + + assert.deepStrictEqual(response.pathItems.length, 1); + assert.deepStrictEqual(response.pathItems[0].name, fileName); + }); + + it("Should work with special blob name characters @loki @sql", async () => { + const specialName = + "汉字. special ~!@#$%^&*()_+`1234567890-={}|[]:\";'<>?,'"; + const fileName: string = getUniqueName(specialName); + const fileClient = fileSystemClient.getFileClient(fileName); + + await fileClient.create(); + await fileClient.getProperties(); + const response = (await fileSystemClient.listPaths({}).byPage().next()) + .value; + + assert.deepStrictEqual(response.pathItems.length, 1); + assert.deepStrictEqual(response.pathItems[0].name, fileName); + }); + + it("Should work with special blob name characters in URL string @loki @sql", async () => { + const specialName = + "汉字. special ~!@#$%^&*()_+`1234567890-={}|[]:\";'<>?,'"; + const fileName: string = getUniqueName(specialName); + const fileClient = new DataLakeFileClient( + // There are 2 special cases for a URL string: + // Escape "%" when creating XxxClient object with URL strings + // Escape "?" otherwise string after "?" will be treated as URL parameters + appendToURLPath( + fileSystemClient.url, + fileName.replace(/%/g, "%25").replace(/\?/g, "%3F") + ), + (fileSystemClient as any).pipeline + ); + + await fileClient.create(); + await fileClient.getProperties(); + const response = ( + await fileSystemClient + .listPaths({ + // NOTICE: Azure Storage Server will replace "\" with "/" in the blob names + // .replace(/\\/g, "/") + }) + .byPage() + .next() + ).value; + + assert.deepStrictEqual(response.pathItems.length, 1); + assert.deepStrictEqual(response.pathItems[0].name, fileName); + }); + + it("Should work with special blob name Russian URI encoded @loki @sql", async () => { + const fileName: string = getUniqueName("ру́сский язы́к"); + const fileNameEncoded: string = encodeURIComponent(fileName); + const fileClient = fileSystemClient.getFileClient(fileNameEncoded); + + await fileClient.create(); + await fileClient.getProperties(); + const response = (await fileSystemClient.listPaths({}).byPage().next()) + .value; + + assert.deepStrictEqual(response.pathItems.length, 1); + assert.deepStrictEqual(response.pathItems[0].name, fileNameEncoded); + }); + + it("Should work with special blob name Russian @loki @sql", async () => { + const fileName: string = getUniqueName("ру́сский язы́к"); + const fileClient = fileSystemClient.getFileClient(fileName); + + await fileClient.create(); + await fileClient.getProperties(); + const response = (await fileSystemClient.listPaths({}).byPage().next()) + .value; + + assert.deepStrictEqual(response.pathItems.length, 1); + assert.deepStrictEqual(response.pathItems[0].name, fileName); + }); + + it("Should work with special blob name Russian in URL string @loki @sql", async () => { + const fileName: string = getUniqueName("ру́сский язы́к"); + const fileClient = new DataLakeFileClient( + appendToURLPath(fileSystemClient.url, fileName), + (fileSystemClient as any).pipeline + ); + + await fileClient.create(); + await fileClient.getProperties(); + const response = (await fileSystemClient.listPaths({}).byPage().next()) + .value; + + assert.deepStrictEqual(response.pathItems.length, 1); + assert.deepStrictEqual(response.pathItems[0].name, fileName); + }); + + it("Should work with special blob name Arabic URI encoded @loki @sql", async () => { + const fileName: string = getUniqueName("عربيعربى"); + const fileNameEncoded: string = encodeURIComponent(fileName); + const fileClient = fileSystemClient.getFileClient(fileNameEncoded); + + await fileClient.create(); + await fileClient.getProperties(); + const response = (await fileSystemClient.listPaths({}).byPage().next()) + .value; + + assert.deepStrictEqual(response.pathItems.length, 1); + assert.deepStrictEqual(response.pathItems[0].name, fileNameEncoded); + }); + + it("Should work with special blob name Arabic @loki @sql", async () => { + const fileName: string = getUniqueName("عربيعربى"); + const fileClient = fileSystemClient.getFileClient(fileName); + + await fileClient.create(); + await fileClient.getProperties(); + const response = (await fileSystemClient.listPaths({}).byPage().next()) + .value; + + assert.deepStrictEqual(response.pathItems.length, 1); + assert.deepStrictEqual(response.pathItems[0].name, fileName); + }); + + it("Should work with special blob name Arabic in URL string @loki @sql", async () => { + const fileName: string = getUniqueName("عربيعربى"); + const fileClient = new DataLakeFileClient( + appendToURLPath(fileSystemClient.url, fileName), + (fileSystemClient as any).pipeline + ); + + await fileClient.create(); + await fileClient.getProperties(); + const response = (await fileSystemClient.listPaths({}).byPage().next()) + .value; + + assert.deepStrictEqual(response.pathItems.length, 1); + assert.deepStrictEqual(response.pathItems[0].name, fileName); + }); + + it("Should work with special blob name Japanese URI encoded @loki @sql", async () => { + const fileName: string = getUniqueName("にっぽんごにほんご"); + const fileNameEncoded: string = encodeURIComponent(fileName); + const fileClient = fileSystemClient.getFileClient(fileNameEncoded); + + await fileClient.create(); + await fileClient.getProperties(); + const response = (await fileSystemClient.listPaths({}).byPage().next()) + .value; + + assert.deepStrictEqual(response.pathItems.length, 1); + assert.deepStrictEqual(response.pathItems[0].name, fileNameEncoded); + }); + + it("Should work with special blob name Japanese @loki @sql", async () => { + const fileName: string = getUniqueName("にっぽんごにほんご"); + const fileClient = fileSystemClient.getFileClient(fileName); + + await fileClient.create(); + await fileClient.getProperties(); + const response = (await fileSystemClient.listPaths({}).byPage().next()) + .value; + + assert.deepStrictEqual(response.pathItems.length, 1); + assert.deepStrictEqual(response.pathItems[0].name, fileName); + }); + + it("Should work with special blob name Japanese in URL string @loki @sql", async () => { + const fileName: string = getUniqueName("にっぽんごにほんご"); + const fileClient = new DataLakeFileClient( + appendToURLPath(fileSystemClient.url, fileName), + (fileSystemClient as any).pipeline + ); + + await fileClient.create(); + await fileClient.getProperties(); + const response = (await fileSystemClient.listPaths({}).byPage().next()) + .value; + + assert.deepStrictEqual(response.pathItems.length, 1); + assert.deepStrictEqual(response.pathItems[0].name, fileName); + }); +}); diff --git a/tests/dfs/authentication.test.ts b/tests/dfs/authentication.test.ts new file mode 100644 index 000000000..79a59b82c --- /dev/null +++ b/tests/dfs/authentication.test.ts @@ -0,0 +1,154 @@ +import * as assert from "assert"; + +import { + AnonymousCredential, + DataLakeServiceClient, + newPipeline, + StorageSharedKeyCredential +} from "@azure/storage-file-datalake"; + +import { configLogger } from "../../src/common/Logger"; +import { + EMULATOR_ACCOUNT_KEY, + EMULATOR_ACCOUNT_NAME, + getUniqueName +} from "../testutils"; +import BlobTestServerFactory from "../BlobTestServerFactory"; + +// Set true to enable debug log +configLogger(false); + +describe("Authentication", () => { + const factory = new BlobTestServerFactory(true); + const server = factory.createServer(); + + const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`; + + before(async () => { + await server.start(); + }); + + after(async () => { + await server.close(); + await server.clean(); + }); + + it(`Should not work without credential @loki @sql`, async () => { + const serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline(new AnonymousCredential(), { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + + const containerName: string = getUniqueName("1container-with-dash"); + const containerClient = serviceClient.getFileSystemClient(containerName); + + let err; + try { + await containerClient.create(); + } catch (error) { + err = error; + } finally { + if (err === undefined) { + try { + await containerClient.delete(); + } catch (error) { + /* Noop */ + } + assert.fail(); + } + } + }); + + it(`Should not work without correct account name @loki @sql`, async () => { + const serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline( + new StorageSharedKeyCredential("invalid", EMULATOR_ACCOUNT_KEY), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ) + ); + + const containerName: string = getUniqueName("1container-with-dash"); + const containerClient = serviceClient.getFileSystemClient(containerName); + + let err; + try { + await containerClient.create(); + } catch (error) { + err = error; + } finally { + if (err === undefined) { + try { + await containerClient.delete(); + } catch (error) { + /* Noop */ + } + assert.fail(); + } + } + }); + + it(`Should not work without correct account key @loki @sql`, async () => { + const serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline( + new StorageSharedKeyCredential(EMULATOR_ACCOUNT_NAME, "invalidkey"), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ) + ); + + const containerName: string = getUniqueName("1container-with-dash"); + const containerClient = serviceClient.getFileSystemClient(containerName); + + let err; + try { + await containerClient.create(); + } catch (error) { + err = error; + } finally { + if (err === undefined) { + try { + await containerClient.delete(); + } catch (error) { + /* Noop */ + } + assert.fail(); + } + } + }); + + it(`Should work with correct shared key @loki @sql`, async () => { + const serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ) + ); + + const containerName: string = getUniqueName("1container-with-dash"); + const containerClient = serviceClient.getFileSystemClient(containerName); + + await containerClient.create(); + await containerClient.delete(); + }); +}); diff --git a/tests/dfs/blobCorsRequest.test.ts b/tests/dfs/blobCorsRequest.test.ts new file mode 100644 index 000000000..d2aae3ff8 --- /dev/null +++ b/tests/dfs/blobCorsRequest.test.ts @@ -0,0 +1,878 @@ +import * as assert from "assert"; + +import { + DataLakeServiceClient, + newPipeline, + RestError, + StorageSharedKeyCredential +} from "@azure/storage-file-datalake"; + +import { configLogger } from "../../src/common/Logger"; +import { + EMULATOR_ACCOUNT_KEY, + EMULATOR_ACCOUNT_NAME, + sleep +} from "../testutils"; +import BlobTestServerFactory from "../BlobTestServerFactory"; +import OPTIONSRequestPolicyFactory from "../blob/RequestPolicy/OPTIONSRequestPolicyFactory"; +import OriginPolicyFactory from "../blob/RequestPolicy/OriginPolicyFactory"; + +// Set true to enable debug log +configLogger(false); + +describe("Blob Cors requests test", () => { + const factory = new BlobTestServerFactory(true); + const server = factory.createServer(); + + const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`; + const serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ) + ); + + before(async () => { + await server.start(); + }); + + after(async () => { + await server.close(); + await server.clean(); + }); + + it("OPTIONS request without cors rules in server should be fail @loki @sql", async () => { + const serviceProperties = await serviceClient.getProperties(); + serviceProperties.cors = []; + await serviceClient.setProperties(serviceProperties); + + const origin = "Origin"; + const requestMethod = "GET"; + + const pipeline = newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + pipeline.factories.unshift( + new OPTIONSRequestPolicyFactory(origin, requestMethod) + ); + const serviceClientForOptions = new DataLakeServiceClient( + baseURL, + pipeline + ); + + let error; + try { + await serviceClientForOptions.getProperties(); + } catch (err) { + error = err; + } + + assert.ok(error.statusCode === 403); + assert.ok( + error.message.includes( + "CORS not enabled or no matching rule found for this request." + ) + ); + }); + + it("OPTIONS request should not work without matching cors rules @loki @sql", async () => { + const serviceProperties = await serviceClient.getProperties(); + + const newCORS = { + allowedHeaders: "header", + allowedMethods: "GET", + allowedOrigins: "test", + exposedHeaders: "*", + maxAgeInSeconds: 8888 + }; + + serviceProperties.cors = [newCORS]; + + await serviceClient.setProperties(serviceProperties); + + await sleep(100); + + let origin = "Origin"; + let requestMethod = "GET"; + + let pipeline = newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + pipeline.factories.unshift( + new OPTIONSRequestPolicyFactory(origin, requestMethod) + ); + let serviceClientForOptions = new DataLakeServiceClient(baseURL, pipeline); + + let error; + try { + await serviceClientForOptions.getProperties(); + } catch (err) { + error = err; + } + + assert.ok(error.statusCode === 403); + assert.ok( + error.message.includes( + "CORS not enabled or no matching rule found for this request." + ) + ); + + origin = "test"; + requestMethod = "GET"; + + pipeline = newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + pipeline.factories.unshift( + new OPTIONSRequestPolicyFactory(origin, requestMethod) + ); + serviceClientForOptions = new DataLakeServiceClient(baseURL, pipeline); + + const res = await serviceClientForOptions.getProperties(); + assert.ok(res._response.status === 200); + }); + + it("OPTIONS request should not work without Origin header or matching allowedOrigins @loki @sql", async () => { + const serviceProperties = await serviceClient.getProperties(); + + const newCORS = { + allowedHeaders: "header", + allowedMethods: "GET", + allowedOrigins: "test", + exposedHeaders: "*", + maxAgeInSeconds: 8888 + }; + + serviceProperties.cors = [newCORS]; + + await serviceClient.setProperties(serviceProperties); + + await sleep(100); + + const origin = "Origin"; + const requestMethod = "GET"; + + let pipeline = newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + pipeline.factories.unshift( + new OPTIONSRequestPolicyFactory(origin, requestMethod) + ); + let serviceClientForOptions = new DataLakeServiceClient(baseURL, pipeline); + + let error; + try { + await serviceClientForOptions.getProperties(); + } catch (err) { + error = err; + } + + assert.ok(error.statusCode === 403); + assert.ok( + error.message.includes( + "CORS not enabled or no matching rule found for this request." + ) + ); + + pipeline = newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + pipeline.factories.unshift( + new OPTIONSRequestPolicyFactory(undefined, requestMethod) + ); + serviceClientForOptions = new DataLakeServiceClient(baseURL, pipeline); + + try { + await serviceClientForOptions.getProperties(); + } catch (err) { + error = err; + } + + assert.ok(error.statusCode === 403); + assert.ok( + error.message.includes( + "CORS not enabled or no matching rule found for this request." + ) + ); + }); + + it("OPTIONS request should not work without requestMethod header or matching allowedMethods @loki @sql", async () => { + const serviceProperties = await serviceClient.getProperties(); + + const newCORS = { + allowedHeaders: "header", + allowedMethods: "GET", + allowedOrigins: "test", + exposedHeaders: "*", + maxAgeInSeconds: 8888 + }; + + serviceProperties.cors = [newCORS]; + + await serviceClient.setProperties(serviceProperties); + + await sleep(100); + + const origin = "test"; + const requestMethod = "PUT"; + + let pipeline = newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + pipeline.factories.unshift( + new OPTIONSRequestPolicyFactory(origin, requestMethod) + ); + let serviceClientForOptions = new DataLakeServiceClient(baseURL, pipeline); + + let error; + try { + await serviceClientForOptions.getProperties(); + } catch (err) { + error = err; + } + + assert.ok(error.statusCode === 403); + assert.ok( + error.message.includes( + "CORS not enabled or no matching rule found for this request." + ) + ); + + pipeline = newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + pipeline.factories.unshift( + new OPTIONSRequestPolicyFactory(origin, undefined) + ); + serviceClientForOptions = new DataLakeServiceClient(baseURL, pipeline); + + try { + await serviceClientForOptions.getProperties(); + } catch (err) { + error = err; + } + + assert.ok(error.statusCode === 400); + assert.ok(error.message.includes("A required CORS header is not present.")); + }); + + it("OPTIONS request should check the defined requestHeaders @loki @sql", async () => { + const serviceProperties = await serviceClient.getProperties(); + + const newCORS = [ + { + allowedHeaders: "header", + allowedMethods: "GET", + allowedOrigins: "test", + exposedHeaders: "*", + maxAgeInSeconds: 8888 + }, + { + allowedHeaders: "*", + allowedMethods: "PUT", + allowedOrigins: "test", + exposedHeaders: "*", + maxAgeInSeconds: 8888 + }, + { + allowedHeaders: "head*", + allowedMethods: "POST", + allowedOrigins: "test", + exposedHeaders: "*", + maxAgeInSeconds: 8888 + } + ]; + + serviceProperties.cors = newCORS; + + await serviceClient.setProperties(serviceProperties); + + await sleep(100); + + // No match + let origin = "test"; + let requestMethod = "GET"; + let reqestHeaders = "head"; + + let pipeline = newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + pipeline.factories.unshift( + new OPTIONSRequestPolicyFactory(origin, requestMethod, reqestHeaders) + ); + let serviceClientForOptions = new DataLakeServiceClient(baseURL, pipeline); + + let error; + try { + await serviceClientForOptions.getProperties(); + } catch (err) { + error = err; + } + + assert.ok(error.statusCode === 403); + assert.ok( + error.message.includes( + "CORS not enabled or no matching rule found for this request." + ) + ); + + // Match first cors. + origin = "test"; + requestMethod = "GET"; + reqestHeaders = "header"; + + pipeline = newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + pipeline.factories.unshift( + new OPTIONSRequestPolicyFactory(origin, requestMethod, reqestHeaders) + ); + serviceClientForOptions = new DataLakeServiceClient(baseURL, pipeline); + + let res = await serviceClientForOptions.getProperties(); + assert.ok(res._response.status === 200); + + // Match second cors. + origin = "test"; + requestMethod = "PUT"; + reqestHeaders = "head"; + + pipeline = newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + pipeline.factories.unshift( + new OPTIONSRequestPolicyFactory(origin, requestMethod, reqestHeaders) + ); + serviceClientForOptions = new DataLakeServiceClient(baseURL, pipeline); + + res = await serviceClientForOptions.getProperties(); + assert.ok(res._response.status === 200); + + // No match. + origin = "test"; + requestMethod = "POST"; + reqestHeaders = "hea"; + + pipeline = newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + pipeline.factories.unshift( + new OPTIONSRequestPolicyFactory(origin, requestMethod, reqestHeaders) + ); + serviceClientForOptions = new DataLakeServiceClient(baseURL, pipeline); + + error; + try { + await serviceClientForOptions.getProperties(); + } catch (err) { + error = err; + } + + assert.ok(error.statusCode === 403); + assert.ok( + error.message.includes( + "CORS not enabled or no matching rule found for this request." + ) + ); + + // Match third cors. + origin = "test"; + requestMethod = "POST"; + reqestHeaders = "headerheader"; + + pipeline = newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + pipeline.factories.unshift( + new OPTIONSRequestPolicyFactory(origin, requestMethod, reqestHeaders) + ); + serviceClientForOptions = new DataLakeServiceClient(baseURL, pipeline); + + res = await serviceClientForOptions.getProperties(); + assert.ok(res._response.status === 200); + }); + + it("OPTIONS request should work with matching rule containing Origion * @loki @sql", async () => { + const serviceProperties = await serviceClient.getProperties(); + + const newCORS = { + allowedHeaders: "header", + allowedMethods: "GET", + allowedOrigins: "*", + exposedHeaders: "*", + maxAgeInSeconds: 8888 + }; + + serviceProperties.cors = [newCORS]; + + await serviceClient.setProperties(serviceProperties); + + await sleep(100); + + const origin = "anyOrigin"; + const requestMethod = "GET"; + + const pipeline = newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + pipeline.factories.unshift( + new OPTIONSRequestPolicyFactory(origin, requestMethod) + ); + const serviceClientForOptions = new DataLakeServiceClient( + baseURL, + pipeline + ); + + const res = await serviceClientForOptions.getProperties(); + assert.ok(res._response.status === 200); + }); + + context( + "OPTIONS request should work with matching rule containing wildcard in Origin @loki @sql", + async () => { + const testCases = [ + { origin: undefined, expected: 403 }, + { origin: "contoso.com", expected: 403 }, + { origin: "bar.notcontoso.com", expected: 403 }, + { origin: "foo.contoso.com", expected: 200 }, + { origin: "foo.bar.baz.contoso.com", expected: 200 }, + { origin: "foo.CONTOSO.com", expected: 200 } + ]; + + testCases.forEach(async (testCase) => { + it(`${testCase.origin}`, async () => { + const serviceProperties = await serviceClient.getProperties(); + + const newCORS = { + allowedHeaders: "header", + allowedMethods: "GET", + allowedOrigins: "*.contoso.com", + exposedHeaders: "*", + maxAgeInSeconds: 8888 + }; + + serviceProperties.cors = [newCORS]; + + await serviceClient.setProperties(serviceProperties); + + await sleep(100); + + const origin = testCase.origin; + const requestMethod = "GET"; + const expectedStatus = testCase.expected; + + const pipeline = newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + pipeline.factories.unshift( + new OPTIONSRequestPolicyFactory(origin, requestMethod) + ); + const serviceClientForOptions = new DataLakeServiceClient( + baseURL, + pipeline + ); + + let status: number = 0; + try { + const res = await serviceClientForOptions.getProperties(); + status = res._response.status; + } catch (e: any) { + if (!(e instanceof RestError)) { + throw e; + } + + status = e.response?.status || 0; + } + + assert.ok(status === expectedStatus); + }); + }); + } + ); + + it("Response of request to service without cors rules should not contains cors info @loki @sql", async () => { + const serviceProperties = await serviceClient.getProperties(); + + serviceProperties.cors = []; + + await serviceClient.setProperties(serviceProperties); + + await sleep(100); + + const origin = "anyOrigin"; + const pipeline = newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + pipeline.factories.unshift(new OriginPolicyFactory(origin)); + const serviceClientWithOrigin = new DataLakeServiceClient( + baseURL, + pipeline + ); + + const res: any = await serviceClientWithOrigin.getProperties(); + + assert.ok(res["access-control-allow-origin"] === undefined); + assert.ok(res["access-control-expose-headers"] === undefined); + assert.ok(res.vary === undefined); + }); + + it("Service with mismatching cors rules should response header Vary @loki @sql", async () => { + const serviceProperties = await serviceClient.getProperties(); + + const newCORS = { + allowedHeaders: "header", + allowedMethods: "GET", + allowedOrigins: "test", + exposedHeaders: "*", + maxAgeInSeconds: 8888 + }; + + serviceProperties.cors = [newCORS]; + + await serviceClient.setProperties(serviceProperties); + + await sleep(100); + + const origin = "anyOrigin"; + const pipeline = newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + pipeline.factories.unshift(new OriginPolicyFactory(origin)); + const serviceClientWithOrigin = new DataLakeServiceClient( + baseURL, + pipeline + ); + + let res: any = await serviceClientWithOrigin.getProperties(); + assert.ok(res.vary !== undefined); + + res = await serviceClient.getProperties(); + assert.ok(res.vary === undefined); + }); + + it("Request Match rule exists that allows all origins (*) @loki @sql", async () => { + const serviceProperties = await serviceClient.getProperties(); + + const newCORS = { + allowedHeaders: "header", + allowedMethods: "GET", + allowedOrigins: "*", + exposedHeaders: "*", + maxAgeInSeconds: 8888 + }; + + serviceProperties.cors = [newCORS]; + + await serviceClient.setProperties(serviceProperties); + + await sleep(100); + + const origin = "anyOrigin"; + const pipeline = newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + pipeline.factories.unshift(new OriginPolicyFactory(origin)); + const serviceClientWithOrigin = new DataLakeServiceClient( + baseURL, + pipeline + ); + + let res: any = await serviceClientWithOrigin.getProperties(); + assert.ok(res["access-control-allow-origin"] === "*"); + assert.ok(res.vary === undefined); + assert.ok(res["access-control-expose-headers"] !== undefined); + + res = await serviceClient.getProperties(); + assert.ok(res["access-control-allow-origin"] === undefined); + assert.ok(res.vary === undefined); + assert.ok(res["access-control-expose-headers"] === undefined); + }); + + it("Request Match rule exists for exact origin @loki @sql", async () => { + const serviceProperties = await serviceClient.getProperties(); + + const newCORS = { + allowedHeaders: "header", + allowedMethods: "GET", + allowedOrigins: "exactOrigin", + exposedHeaders: "*", + maxAgeInSeconds: 8888 + }; + + serviceProperties.cors = [newCORS]; + + await serviceClient.setProperties(serviceProperties); + + await sleep(100); + + const origin = "exactOrigin"; + const pipeline = newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + pipeline.factories.unshift(new OriginPolicyFactory(origin)); + const serviceClientWithOrigin = new DataLakeServiceClient( + baseURL, + pipeline + ); + + const res: any = await serviceClientWithOrigin.getProperties(); + assert.ok(res["access-control-allow-origin"] === origin); + assert.ok(res.vary !== undefined); + assert.ok(res["access-control-expose-headers"] !== undefined); + }); + + it("Requests with error response should apply for CORS @loki @sql", async () => { + const serviceProperties = await serviceClient.getProperties(); + + const newCORS = { + allowedHeaders: "header", + allowedMethods: "GET", + allowedOrigins: "exactOrigin", + exposedHeaders: "*", + maxAgeInSeconds: 8888 + }; + + serviceProperties.cors = [newCORS]; + + await serviceClient.setProperties(serviceProperties); + + await sleep(100); + + const origin = "exactOrigin"; + const pipeline = newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + pipeline.factories.unshift(new OriginPolicyFactory(origin)); + const serviceClientWithOrigin = new DataLakeServiceClient( + baseURL, + pipeline + ); + + const containerClientWithOrigin = + serviceClientWithOrigin.getFileSystemClient("notexistcontainer"); + + try { + await containerClientWithOrigin.getProperties(); + } catch (err) { + assert.ok( + err.response.headers._headersMap["access-control-allow-origin"] + .value === origin + ); + assert.ok(err.response.headers._headersMap.vary !== undefined); + assert.ok( + err.response.headers._headersMap["access-control-expose-headers"] !== + undefined + ); + } + }); + + it("Request Match rule in sequence @loki @sql", async () => { + const serviceProperties = await serviceClient.getProperties(); + + const newCORS = [ + { + allowedHeaders: "header", + allowedMethods: "GET", + allowedOrigins: "exactOrigin", + exposedHeaders: "*", + maxAgeInSeconds: 8888 + }, + { + allowedHeaders: "header", + allowedMethods: "GET", + allowedOrigins: "*", + exposedHeaders: "*", + maxAgeInSeconds: 8888 + } + ]; + + serviceProperties.cors = newCORS; + + await serviceClient.setProperties(serviceProperties); + + await sleep(100); + + const origin = "exactOrigin"; + const pipeline = newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + pipeline.factories.unshift(new OriginPolicyFactory(origin)); + const serviceClientWithOrigin = new DataLakeServiceClient( + baseURL, + pipeline + ); + + const res: any = await serviceClientWithOrigin.getProperties(); + assert.ok(res["access-control-allow-origin"] === origin); + assert.ok(res.vary !== undefined); + assert.ok(res["access-control-expose-headers"] !== undefined); + }); +}); diff --git a/tests/dfs/bugs.test.ts b/tests/dfs/bugs.test.ts new file mode 100644 index 000000000..1cd0fb96d --- /dev/null +++ b/tests/dfs/bugs.test.ts @@ -0,0 +1,152 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +import assert from "assert"; +import os from "os"; +import { + DataLakeDirectoryClient, + DataLakeFileClient, + DataLakeFileSystemClient, + DataLakeServiceClient, + FileSystemListPathsResponse, + StorageSharedKeyCredential +} from "@azure/storage-file-datalake"; + +import { + bodyToString, + EMULATOR_ACCOUNT_KEY, + EMULATOR_ACCOUNT_NAME, + getUniqueName +} from "../testutils"; +import BlobTestServerFactory from "../BlobTestServerFactory"; + +describe("Bugs", () => { + const factory = new BlobTestServerFactory(true); + const server = factory.createServer(true); + + const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`; + const serviceClient = new DataLakeServiceClient( + baseURL, + new StorageSharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ); + + let fileSystemName: string; + let fileSystemClient: DataLakeFileSystemClient; + let fileName: string; + let fileClient: DataLakeFileClient; + let directoryName: string; + let directoryClient: DataLakeDirectoryClient; + const content = "Hello World"; + + before(async () => { + await server.start(); + }); + + after(async () => { + await server.close(); + await server.clean(); + }); + + beforeEach(async function () { + fileSystemName = getUniqueName("filesystem"); + fileSystemClient = serviceClient.getFileSystemClient(fileSystemName); + await fileSystemClient.createIfNotExists(); + directoryName = getUniqueName("directory"); + directoryClient = fileSystemClient.getDirectoryClient(directoryName); + await directoryClient.create(); + fileName = getUniqueName("file"); + fileClient = fileSystemClient.getFileClient(fileName); + await fileClient.create(); + await fileClient.append(content, 0, content.length); + await fileClient.flush(content.length); + }); + + afterEach(async function () { + await fileSystemClient.deleteIfExists(); + }); + + it("listPaths should work on root @loki @sql", async () => { + await fileSystemClient + .getDirectoryClient(getUniqueName("directory")) + .create(); + await fileSystemClient + .getDirectoryClient(getUniqueName("directory")) + .create(); + await fileSystemClient + .getDirectoryClient(getUniqueName("directory")) + .create(); + await fileSystemClient.getFileClient(getUniqueName("file")).create(); + + const response = (await fileSystemClient.listPaths().byPage().next()) + .value as FileSystemListPathsResponse; + + assert.strictEqual(response.pathItems?.length, 6); + }); + + it("listPaths should not include folders/files with same prefix @loki @sql", async () => { + await fileSystemClient.getDirectoryClient("abc").create(); + await fileSystemClient.getDirectoryClient("abc123").create(); + await fileSystemClient.getDirectoryClient("abc1234").create(); + await fileSystemClient.getFileClient("abc1").create(); + await fileSystemClient.getFileClient("abc12").create(); + + const response = ( + await fileSystemClient.listPaths({ path: "abc" }).byPage().next() + ).value as FileSystemListPathsResponse; + + assert.strictEqual(response.pathItems?.length, 0); + }); + + it("recursive delete should not delete folders/files with same prefix @loki @sql", async () => { + const directoryClient = fileSystemClient.getDirectoryClient("abc"); + await directoryClient.create(); + const directoryClient2 = fileSystemClient.getDirectoryClient("abc123"); + const directoryClient3 = fileSystemClient.getDirectoryClient("abc1234"); + const fileClient1 = fileSystemClient.getFileClient("abc1"); + const fileClient2 = fileSystemClient.getFileClient("abc2"); + await directoryClient2.create(); + await directoryClient3.create(); + await fileClient1.create(); + await fileClient2.create(); + await directoryClient.delete(true); + assert.strictEqual(await directoryClient2.exists(), true); + assert.strictEqual(await directoryClient3.exists(), true); + assert.strictEqual(await fileClient1.exists(), true); + assert.strictEqual(await fileClient2.exists(), true); + }); + + it("multiple append/flush should not overwrite each other @loki @sql", async () => { + await fileClient.create(); + const len = content.length; + await fileClient.append(content, 0, len, { flush: true }); + await fileClient.append(content, len, len, { flush: true }); + await fileClient.append(content, len * 2, len, { flush: true }); + const response = await fileClient.getProperties(); + assert.strictEqual(response.contentLength, len * 3); + const readResponse = await fileClient.read(); + const read = await bodyToString(readResponse, readResponse.contentLength); + assert.strictEqual(read, content + content + content); + }); + + it("file should have default access control @loki @sql", async () => { + assert.ok((await fileClient.getAccessControl()).acl); + assert.ok((await fileClient.getAccessControl()).permissions); + assert.ok((await fileClient.getAccessControl()).owner); + if (os.platform() !== "win32") { + assert.ok((await fileClient.getAccessControl()).group); + } + }); + + it("directory should have default access control @loki @sql", async () => { + assert.ok((await directoryClient.getAccessControl()).acl); + assert.ok((await directoryClient.getAccessControl()).permissions); + assert.ok((await directoryClient.getAccessControl()).owner); + if (os.platform() !== "win32") { + assert.ok((await directoryClient.getAccessControl()).group); + } + }); +}); diff --git a/tests/dfs/https.test.ts b/tests/dfs/https.test.ts new file mode 100644 index 000000000..87b448438 --- /dev/null +++ b/tests/dfs/https.test.ts @@ -0,0 +1,54 @@ +import { + DataLakeServiceClient, + newPipeline, + StorageSharedKeyCredential +} from "@azure/storage-file-datalake"; + +import { configLogger } from "../../src/common/Logger"; +import { + EMULATOR_ACCOUNT_KEY, + EMULATOR_ACCOUNT_NAME, + getUniqueName +} from "../testutils"; +import BlobTestServerFactory from "../BlobTestServerFactory"; + +// Set true to enable debug log +configLogger(false); + +describe("Blob HTTPS", () => { + const factory = new BlobTestServerFactory(true); + const server = factory.createServer(false, false, true); + const baseURL = `https://${server.config.host}:${server.config.port}/devstoreaccount1`; + + before(async () => { + await server.start(); + }); + + after(async () => { + await server.close(); + await server.clean(); + }); + + it(`Should work with correct shared key using HTTPS endpoint @loki @sql`, async () => { + const serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ) + ); + + const containerName: string = getUniqueName("1container-with-dash"); + const containerClient = serviceClient.getFileSystemClient(containerName); + + await containerClient.create(); + await containerClient.delete(); + }); +}); diff --git a/tests/dfs/integration/filesDirMixedApis.test.ts b/tests/dfs/integration/filesDirMixedApis.test.ts new file mode 100644 index 000000000..a4fb169cf --- /dev/null +++ b/tests/dfs/integration/filesDirMixedApis.test.ts @@ -0,0 +1,271 @@ +import assert, { fail } from "assert"; +import { count } from "console"; + +import { BlobServiceClient } from "@azure/storage-blob"; +import { + DataLakeServiceClient, + newPipeline, + StorageSharedKeyCredential +} from "@azure/storage-file-datalake"; + +import { configLogger } from "../../../src/common/Logger"; +import { + bodyToString, + EMULATOR_ACCOUNT_KEY, + EMULATOR_ACCOUNT_NAME, + getUniqueName +} from "../../testutils"; +import BlobTestServerFactory from "../../BlobTestServerFactory"; + +// Set true to enable debug log +configLogger(false); + +describe("DirectoryAndFileApis", () => { + const factory = new BlobTestServerFactory(true); + const server = factory.createServer(); + + const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`; + const serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ) + ); + + const blobServiceClient = new BlobServiceClient( + baseURL, + newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ) + ); + + const fileSytemName: string = getUniqueName("filesystem"); + const fileSystemClient = serviceClient.getFileSystemClient(fileSytemName); + const parentDirectoryName: string = getUniqueName("parentDirectory"); + const parentDirectoryClient = + fileSystemClient.getDirectoryClient(parentDirectoryName); + const chilDirectoryName: string = getUniqueName("childDirectory"); + const childDirectoryClient = + parentDirectoryClient.getSubdirectoryClient(chilDirectoryName); + const grandChildDirectoryName = getUniqueName("grandChildDirectory"); + const grandChildDirectoryClient = childDirectoryClient.getSubdirectoryClient( + grandChildDirectoryName + ); + const file1Name: string = getUniqueName("file1"); + const file1Client = grandChildDirectoryClient.getFileClient(file1Name); + const file2Name: string = getUniqueName("file2"); + const file2Client = grandChildDirectoryClient.getFileClient(file2Name); + + let containerClient = blobServiceClient.getContainerClient(fileSytemName); + let blob1Client = containerClient.getBlobClient( + `${parentDirectoryName}/${chilDirectoryName}/${grandChildDirectoryName}/${file1Name}` + ); + let blob2Client = containerClient.getBlobClient( + `${parentDirectoryName}/${chilDirectoryName}/${grandChildDirectoryName}/${file2Name}` + ); + + const content = "Hello World"; + + before(async () => { + await server.start(); + }); + + after(async () => { + await fileSystemClient.delete(); + await server.close(); + await server.clean(); + }); + + it("create directorys @loki @sql", async () => { + await fileSystemClient.createIfNotExists(); + await parentDirectoryClient.deleteIfExists(true); + //should create parent as well; + await grandChildDirectoryClient.create(); + assert.strictEqual(await grandChildDirectoryClient.exists(), true); + assert.strictEqual(await childDirectoryClient.exists(), true); + assert.strictEqual(await parentDirectoryClient.exists(), true); + }); + + it("create File (DataLake) @loki @sql", async () => { + await file1Client.create(); + assert.strictEqual(await file1Client.exists(), true); + const properties = await file1Client.getProperties(); + assert.strictEqual(properties.contentLength, 0); + await file1Client.delete(); + assert.strictEqual(await file1Client.exists(), false); + }); + + it("create AppendBlob (Blob) @loki @sql", async () => { + await blob1Client.getAppendBlobClient().create(); + assert.strictEqual(await blob1Client.exists(), true); + const properties = await blob1Client.getProperties(); + assert.strictEqual(properties.contentLength, 0); + }); + + it("Append to File (DataLake) @loki @sql", async () => { + await file1Client.append(content, 0, content.length); + await file1Client.flush(content.length); + const properties = await file1Client.getProperties(); + assert.strictEqual(properties.contentLength, content.length); + }); + + it("Append to File (Blob) @loki @sql", async () => { + await blob1Client + .getAppendBlobClient() + .appendBlock(content, content.length); + const properties = await file1Client.getProperties(); + assert.strictEqual(properties.contentLength, content.length * 2); + }); + + it("Append to Non Existing File should fail (DataLake) @loki @sql", async () => { + const nonExistingFileClient = grandChildDirectoryClient.getFileClient( + getUniqueName("non-existing-file") + ); + let error; + try { + await nonExistingFileClient.append(content, 0, content.length); + } catch (err) { + error = err; + assert.strictEqual(err.code, "PathNotFound"); + assert.strictEqual( + err.message.startsWith("The specified path does not exist."), + true + ); + } + + if (!error) fail(); + }); + + it("Flush to Non Existing File should fail (DataLake) @loki @sql", async () => { + const nonExistingFileClient = grandChildDirectoryClient.getFileClient( + getUniqueName("non-existing-file") + ); + let error; + try { + await nonExistingFileClient.flush(content.length); + } catch (err) { + error = err; + assert.strictEqual(err.code, "PathNotFound"); + assert.strictEqual( + err.message.startsWith("The specified path does not exist."), + true + ); + } + + if (!error) fail(); + }); + + it("Append to Non Existing File should fail (Blob) @loki @sql", async () => { + const nonExistingBlobClient = containerClient.getBlobClient( + getUniqueName("non-existing-file") + ); + let error; + try { + await nonExistingBlobClient + .getAppendBlobClient() + .appendBlock(content, content.length); + } catch (err) { + error = err; + assert.strictEqual(err.code, "BlobNotFound"); + assert.strictEqual( + err.message.startsWith("The specified blob does not exist."), + true + ); + } + + if (!error) fail(); + }); + + it("Read File (DataLake) @loki @sql", async () => { + const readContent = await file1Client.readToBuffer(0, count.length * 2); + assert.deepStrictEqual(readContent, Buffer.from(content + content)); + }); + + it("Read File (Blob) @loki @sql", async () => { + const readContent = await blob1Client.downloadToBuffer(0, count.length * 2); + assert.deepStrictEqual(readContent, Buffer.from(content + content)); + }); + + it("Copy File (DataLake) [Read Then upload no direct copy] @loki @sql", async () => { + assert.strictEqual(await file1Client.exists(), true); + assert.strictEqual(await file2Client.exists(), false); + const readResponse = await file1Client.read(); + const readContent = await bodyToString(readResponse); + await file2Client.create(); + await file2Client.append(readContent, 0, readContent.length, { + flush: true + }); + assert.strictEqual(await file1Client.exists(), true); + assert.strictEqual(await file2Client.exists(), true); + const writtenResponse = await file2Client.read(); + const writtenContent = await bodyToString(writtenResponse); + assert.deepStrictEqual(readContent, writtenContent); + await file2Client.delete(); + }); + + it("Copy File (Blob) @loki @sql", async () => { + assert.strictEqual(await blob1Client.exists(), true); + assert.strictEqual(await blob2Client.exists(), false); + await blob2Client.syncCopyFromURL(blob1Client.url); + assert.strictEqual(await blob1Client.exists(), true); + assert.strictEqual(await blob2Client.exists(), true); + const result1 = await blob1Client.download(); + const result2 = await blob2Client.download(); + const readContent1 = await bodyToString(result1, result1.contentLength); + const readContent2 = await bodyToString(result2, result2.contentLength); + assert.deepStrictEqual(readContent1, readContent2); + }); + + it.skip("Move/Rename Directory [in azure-data-lake current version only works with production style url, in normal mode it doesn't send account name in url] (DataLake) @loki @sql", async () => { + const destDirClient = parentDirectoryClient.getSubdirectoryClient( + getUniqueName("sourcedir") + ); + assert.strictEqual(await childDirectoryClient.exists(), true); + assert.strictEqual(await destDirClient.exists(), false); + await childDirectoryClient.move(destDirClient.name); + assert.strictEqual(await childDirectoryClient.exists(), false); + assert.strictEqual(await grandChildDirectoryClient.exists(), false); + assert.strictEqual(await file1Client.exists(), false); + assert.strictEqual(await file2Client.exists(), false); + assert.strictEqual(await destDirClient.exists(), true); + await destDirClient.move(childDirectoryClient.name); + assert.strictEqual(await childDirectoryClient.exists(), true); + assert.strictEqual(await grandChildDirectoryClient.exists(), true); + assert.strictEqual(await file1Client.exists(), true); + assert.strictEqual(await file2Client.exists(), true); + assert.strictEqual(await destDirClient.exists(), false); + }); + + it("Append then read should return empty withoutflush (DataLake) @loki @sql", async () => { + await file1Client.deleteIfExists(); + assert.strictEqual(await file1Client.exists(), false); + await file1Client.create(); + assert.strictEqual(await file1Client.exists(), true); + await file1Client.append(content, 0, content.length); + let readResponse = await file1Client.read(); + let readContent = await bodyToString(readResponse); + assert.strictEqual(readContent.length, 0); + await file1Client.append(content, 0, content.length); + assert.strictEqual(readContent.length, 0); + await file1Client.flush(content.length * 2); + readResponse = await file1Client.read(); + readContent = await bodyToString(readResponse); + assert.deepStrictEqual(readContent, content + content); + }); +}); diff --git a/tests/dfs/oauth.test.ts b/tests/dfs/oauth.test.ts new file mode 100644 index 000000000..2eed8f586 --- /dev/null +++ b/tests/dfs/oauth.test.ts @@ -0,0 +1,891 @@ +import * as assert from "assert"; + +import { + AccountSASPermissions, + AccountSASResourceTypes, + AccountSASServices, + AnonymousCredential, + DataLakeFileSystemClient, + DataLakeServiceClient, + FileSystemSASPermissions, + generateAccountSASQueryParameters, + generateDataLakeSASQueryParameters, + newPipeline, + SASProtocol, + StorageSharedKeyCredential +} from "@azure/storage-file-datalake"; + +import { configLogger } from "../../src/common/Logger"; +import { SimpleTokenCredential } from "../simpleTokenCredential"; +import { + EMULATOR_ACCOUNT_KEY, + EMULATOR_ACCOUNT_NAME, + generateJWTToken, + getUniqueName, + upload +} from "../testutils"; +import BlobTestServerFactory from "../BlobTestServerFactory"; + +// Set true to enable debug log +configLogger(false); + +describe("Blob OAuth Basic", () => { + const factory = new BlobTestServerFactory(true); + let server = factory.createServer(false, false, true, "basic"); + const baseURL = `https://${server.config.host}:${server.config.port}/devstoreaccount1`; + + before(async () => { + await server.start(); + }); + + after(async () => { + await server.close(); + await server.clean(); + }); + + it(`Should work with create container @loki @sql`, async () => { + const token = generateJWTToken( + new Date("2019/01/01"), + new Date("2019/01/01"), + new Date("2100/01/01"), + "https://sts.windows-ppe.net/ab1f708d-50f6-404c-a006-d71b2ac7a606/", + "https://storage.azure.com", + "user_impersonation", + "23657296-5cd5-45b0-a809-d972a7f4dfe1", + "dd0d0df1-06c3-436c-8034-4b9a153097ce" + ); + + const serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline(new SimpleTokenCredential(token), { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + + const containerName: string = getUniqueName("1container-with-dash"); + const containerClient = serviceClient.getFileSystemClient(containerName); + + await containerClient.create(); + await containerClient.delete(); + }); + + it(`Should work with delegation SAS @loki @sql`, async () => { + const token = generateJWTToken( + new Date("2019/01/01"), + new Date("2019/01/01"), + new Date("2100/01/01"), + "https://sts.windows-ppe.net/ab1f708d-50f6-404c-a006-d71b2ac7a606/", + "https://storage.azure.com", + "user_impersonation", + "23657296-5cd5-45b0-a809-d972a7f4dfe1", + "dd0d0df1-06c3-436c-8034-4b9a153097ce" + ); + + const serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline(new SimpleTokenCredential(token), { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + + const startTime = new Date(); + startTime.setHours(startTime.getHours() - 1); + const expiryTime = new Date(); + expiryTime.setDate(expiryTime.getDate() + 1); + + const userDelegationKey = await serviceClient.getUserDelegationKey( + startTime, + expiryTime + ); + + const containerName: string = getUniqueName("1container-with-dash"); + + const sasExpirytime = new Date(); + sasExpirytime.setHours(sasExpirytime.getHours() + 1); + + const containerSAS = generateDataLakeSASQueryParameters( + { + fileSystemName: containerName, + expiresOn: sasExpirytime, + permissions: FileSystemSASPermissions.parse("racwdl") + }, + userDelegationKey, + "devstoreaccount1" + ); + + const containerClient = new DataLakeFileSystemClient( + `${serviceClient.url}/${containerName}?${containerSAS}`, + newPipeline(new AnonymousCredential()) + ); + await containerClient.create(); + await containerClient.delete(); + }); + + it(`Should work with delegation SAS container client doing blob upload @loki @sql`, async () => { + const token = generateJWTToken( + new Date("2019/01/01"), + new Date("2019/01/01"), + new Date("2100/01/01"), + "https://sts.windows-ppe.net/ab1f708d-50f6-404c-a006-d71b2ac7a606/", + "https://storage.azure.com", + "user_impersonation", + "23657296-5cd5-45b0-a809-d972a7f4dfe1", + "dd0d0df1-06c3-436c-8034-4b9a153097ce" + ); + + const serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline(new SimpleTokenCredential(token), { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + + const startTime = new Date(); + startTime.setHours(startTime.getHours() - 1); + const expiryTime = new Date(); + expiryTime.setDate(expiryTime.getDate() + 1); + + const userDelegationKey = await serviceClient.getUserDelegationKey( + startTime, + expiryTime + ); + + const containerName: string = getUniqueName("1container-with-dash"); + + const sasExpirytime = new Date(); + sasExpirytime.setHours(sasExpirytime.getHours() + 1); + + const containerSAS = generateDataLakeSASQueryParameters( + { + fileSystemName: containerName, + expiresOn: sasExpirytime, + permissions: FileSystemSASPermissions.parse("racwdl") + }, + userDelegationKey, + "devstoreaccount1" + ); + + const containerClient = new DataLakeFileSystemClient( + `${serviceClient.url}/${containerName}?${containerSAS}`, + newPipeline(new AnonymousCredential()) + ); + await containerClient.create(); + const blobClient = await containerClient.getFileClient("test"); + const data = "Test Data"; + await upload(blobClient, data); + await containerClient.delete(); + }); + + it(`Should fail with delegation SAS with invalid time duration @loki @sql`, async () => { + const token = generateJWTToken( + new Date("2019/01/01"), + new Date("2019/01/01"), + new Date("2100/01/01"), + "https://sts.windows-ppe.net/ab1f708d-50f6-404c-a006-d71b2ac7a606/", + "https://storage.azure.com", + "user_impersonation", + "23657296-5cd5-45b0-a809-d972a7f4dfe1", + "dd0d0df1-06c3-436c-8034-4b9a153097ce" + ); + + const serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline(new SimpleTokenCredential(token), { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + const containerName: string = getUniqueName("1container-with-dash"); + + // Later user delegation key start time + let startTime = new Date(); + startTime.setMinutes(startTime.getMinutes() + 20); + let expiryTime = new Date(); + expiryTime.setDate(expiryTime.getDate() + 1); + let userDelegationKey = await serviceClient.getUserDelegationKey( + startTime, + expiryTime + ); + + let sasExpirytime = new Date(); + sasExpirytime.setHours(sasExpirytime.getHours() + 1); + + let containerSAS = generateDataLakeSASQueryParameters( + { + fileSystemName: containerName, + expiresOn: sasExpirytime, + permissions: FileSystemSASPermissions.parse("racwdl") + }, + userDelegationKey, + "devstoreaccount1" + ); + + let containerClient = new DataLakeFileSystemClient( + `${serviceClient.url}/${containerName}?${containerSAS}`, + newPipeline(new AnonymousCredential()) + ); + let failed = false; + try { + await containerClient.create(); + } catch (err) { + failed = true; + assert.equal(err.statusCode, 403); + } + assert.ok(failed); + + // Eearlier user delegation key expirty time + startTime = new Date(); + startTime.setDate(startTime.getDate() - 1); + expiryTime = new Date(); + expiryTime.setMinutes(expiryTime.getMinutes() - 1); + userDelegationKey = await serviceClient.getUserDelegationKey( + startTime, + expiryTime + ); + + sasExpirytime = new Date(); + sasExpirytime.setHours(sasExpirytime.getHours() + 1); + + containerSAS = generateDataLakeSASQueryParameters( + { + fileSystemName: containerName, + expiresOn: sasExpirytime, + permissions: FileSystemSASPermissions.parse("racwdl") + }, + userDelegationKey, + "devstoreaccount1" + ); + + containerClient = new DataLakeFileSystemClient( + `${serviceClient.url}/${containerName}?${containerSAS}`, + newPipeline(new AnonymousCredential()) + ); + + failed = false; + try { + await containerClient.create(); + } catch (err) { + failed = true; + assert.equal(err.statusCode, 403); + } + assert.ok(failed); + }); + + it(`Should fail with delegation SAS with access policy @loki @sql`, async () => { + const token = generateJWTToken( + new Date("2019/01/01"), + new Date("2019/01/01"), + new Date("2100/01/01"), + "https://sts.windows-ppe.net/ab1f708d-50f6-404c-a006-d71b2ac7a606/", + "https://storage.azure.com", + "user_impersonation", + "23657296-5cd5-45b0-a809-d972a7f4dfe1", + "dd0d0df1-06c3-436c-8034-4b9a153097ce" + ); + + const serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline(new SimpleTokenCredential(token), { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + + const startTime = new Date(); + startTime.setHours(startTime.getHours() - 1); + const expiryTime = new Date(); + expiryTime.setDate(expiryTime.getDate() + 1); + const userDelegationKey = await serviceClient.getUserDelegationKey( + startTime, + expiryTime + ); + + const serviceClientWithAccountKey = new DataLakeServiceClient( + baseURL, + newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ) + ); + const containerName: string = getUniqueName("1container-with-dash"); + const containerClientWithKey = + serviceClientWithAccountKey.getFileSystemClient(containerName); + await containerClientWithKey.create(); + await containerClientWithKey.setAccessPolicy(undefined, [ + { + accessPolicy: { + permissions: "racwdl" + }, + id: "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=" + } + ]); + + const sasExpirytime = new Date(); + sasExpirytime.setHours(sasExpirytime.getHours() + 1); + + const containerSAS = generateDataLakeSASQueryParameters( + { + fileSystemName: containerName, + expiresOn: sasExpirytime, + permissions: FileSystemSASPermissions.parse("racwdl"), + identifier: "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=" + }, + userDelegationKey, + "devstoreaccount1" + ); + + const containerClient = new DataLakeFileSystemClient( + `${serviceClient.url}/${containerName}?${containerSAS}`, + newPipeline(new AnonymousCredential()) + ); + + let failed = false; + try { + await containerClient.getProperties(); + } catch (err) { + failed = true; + assert.equal(err.statusCode, 403); + } + assert.ok(failed); + }); + + it(`Should not work with invalid JWT token @loki @sql`, async () => { + const serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline(new SimpleTokenCredential("invalid token"), { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + + const containerName: string = getUniqueName("1container-with-dash"); + const containerClient = serviceClient.getFileSystemClient(containerName); + + try { + await containerClient.create(); + await containerClient.delete(); + } catch (err) { + assert.deepStrictEqual( + err.message.includes("Server failed to authenticate the request."), + true + ); + return; + } + assert.fail(); + }); + + it(`Should work with valid audiences @loki @sql`, async () => { + const audiences = [ + "https://storage.azure.com", + "https://storage.azure.com/", + "e406a681-f3d4-42a8-90b6-c2b029497af1", + "https://devstoreaccount1.blob.core.windows.net", + "https://devstoreaccount1.blob.core.windows.net/", + "https://devstoreaccount1.blob.core.chinacloudapi.cn", + "https://devstoreaccount1.blob.core.chinacloudapi.cn/", + "https://devstoreaccount1.blob.core.usgovcloudapi.net", + "https://devstoreaccount1.blob.core.usgovcloudapi.net/", + "https://devstoreaccount1.blob.core.cloudapi.de", + "https://devstoreaccount1.blob.core.cloudapi.de/" + ]; + + for (const audience of audiences) { + const token = generateJWTToken( + new Date("2019/01/01"), + new Date("2019/01/01"), + new Date("2100/01/01"), + "https://sts.windows-ppe.net/ab1f708d-50f6-404c-a006-d71b2ac7a606/", + audience, + "user_impersonation", + "23657296-5cd5-45b0-a809-d972a7f4dfe1", + "dd0d0df1-06c3-436c-8034-4b9a153097ce" + ); + + const serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline(new SimpleTokenCredential(token), { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + + const containerName: string = getUniqueName("1container-with-dash"); + const containerClient = serviceClient.getFileSystemClient(containerName); + + await containerClient.create(); + await containerClient.delete(); + } + }); + + it(`Should not work with invalid audiences @loki @sql`, async () => { + const token = generateJWTToken( + new Date("2019/01/01"), + new Date("2019/01/01"), + new Date("2100/01/01"), + "https://sts.windows-ppe.net/ab1f708d-50f6-404c-a006-d71b2ac7a606/", + "https://invalidaccount.blob.core.windows.net", + "user_impersonation", + "23657296-5cd5-45b0-a809-d972a7f4dfe1", + "dd0d0df1-06c3-436c-8034-4b9a153097ce" + ); + + const serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline(new SimpleTokenCredential(token), { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + + const containerName: string = getUniqueName("1container-with-dash"); + const containerClient = serviceClient.getFileSystemClient(containerName); + + try { + await containerClient.create(); + await containerClient.delete(); + } catch (err) { + assert.deepStrictEqual( + err.message.includes("Server failed to authenticate the request."), + true + ); + assert.deepStrictEqual( + err.details.AuthenticationErrorDetail.includes("audience"), + true + ); + return; + } + assert.fail(); + }); + + it(`Should work with valid issuers @loki @sql`, async () => { + const issuerPrefixes = [ + "https://sts.windows.net/", + "https://sts.microsoftonline.de/", + "https://sts.chinacloudapi.cn/", + "https://sts.windows-ppe.net" + ]; + + for (const issuerPrefix of issuerPrefixes) { + const token = generateJWTToken( + new Date("2019/01/01"), + new Date("2019/01/01"), + new Date("2100/01/01"), + `${issuerPrefix}/ab1f708d-50f6-404c-a006-d71b2ac7a606/`, + "e406a681-f3d4-42a8-90b6-c2b029497af1", + "user_impersonation", + "23657296-5cd5-45b0-a809-d972a7f4dfe1", + "dd0d0df1-06c3-436c-8034-4b9a153097ce" + ); + + const serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline(new SimpleTokenCredential(token), { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + + const containerName: string = getUniqueName("1container-with-dash"); + const containerClient = serviceClient.getFileSystemClient(containerName); + + await containerClient.create(); + await containerClient.delete(); + } + }); + + it(`Should not work with invalid issuers @loki @sql`, async () => { + const token = generateJWTToken( + new Date("2019/01/01"), + new Date("2019/01/01"), + new Date("2100/01/01"), + "https://invalidissuer/ab1f708d-50f6-404c-a006-d71b2ac7a606/", + "https://invalidaccount.blob.core.windows.net", + "user_impersonation", + "23657296-5cd5-45b0-a809-d972a7f4dfe1", + "dd0d0df1-06c3-436c-8034-4b9a153097ce" + ); + + const serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline(new SimpleTokenCredential(token), { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + + const containerName: string = getUniqueName("1container-with-dash"); + const containerClient = serviceClient.getFileSystemClient(containerName); + + try { + await containerClient.create(); + await containerClient.delete(); + } catch (err) { + assert.deepStrictEqual( + err.message.includes("Server failed to authenticate the request."), + true + ); + assert.deepStrictEqual( + err.details.AuthenticationErrorDetail.includes("issuer"), + true + ); + return; + } + assert.fail(); + }); + + it(`Should not work with invalid nbf @loki @sql`, async () => { + const token = generateJWTToken( + new Date("2119/01/01"), + new Date("2019/01/01"), + new Date("2100/01/01"), + "https://sts.windows-ppe.net/ab1f708d-50f6-404c-a006-d71b2ac7a606/", + "https://devstoreaccount1.blob.core.windows.net", + "user_impersonation", + "23657296-5cd5-45b0-a809-d972a7f4dfe1", + "dd0d0df1-06c3-436c-8034-4b9a153097ce" + ); + + const serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline(new SimpleTokenCredential(token), { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + + const containerName: string = getUniqueName("1container-with-dash"); + const containerClient = serviceClient.getFileSystemClient(containerName); + + try { + await containerClient.create(); + await containerClient.delete(); + } catch (err) { + assert.deepStrictEqual( + err.message.includes("Server failed to authenticate the request."), + true + ); + assert.deepStrictEqual( + err.details.AuthenticationErrorDetail.includes("Lifetime"), + true + ); + return; + } + assert.fail(); + }); + + it(`Should not work with invalid exp @loki @sql`, async () => { + const token = generateJWTToken( + new Date("2019/01/01"), + new Date("2019/01/01"), + new Date("2019/01/01"), + "https://sts.windows-ppe.net/ab1f708d-50f6-404c-a006-d71b2ac7a606/", + "https://devstoreaccount1.blob.core.windows.net", + "user_impersonation", + "23657296-5cd5-45b0-a809-d972a7f4dfe1", + "dd0d0df1-06c3-436c-8034-4b9a153097ce" + ); + + const serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline(new SimpleTokenCredential(token), { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + + const containerName: string = getUniqueName("1container-with-dash"); + const containerClient = serviceClient.getFileSystemClient(containerName); + + try { + await containerClient.create(); + await containerClient.delete(); + } catch (err) { + assert.deepStrictEqual( + err.message.includes("Server failed to authenticate the request."), + true + ); + assert.deepStrictEqual( + err.details.AuthenticationErrorDetail.includes("expire"), + true + ); + return; + } + assert.fail(); + }); + + it(`Should not work with get container ACL @loki @sql`, async () => { + const token = generateJWTToken( + new Date("2019/01/01"), + new Date("2019/01/01"), + new Date("2100/01/01"), + "https://sts.windows-ppe.net/ab1f708d-50f6-404c-a006-d71b2ac7a606/", + "https://devstoreaccount1.blob.core.windows.net", + "user_impersonation", + "23657296-5cd5-45b0-a809-d972a7f4dfe1", + "dd0d0df1-06c3-436c-8034-4b9a153097ce" + ); + + const serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline(new SimpleTokenCredential(token), { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + + const containerName: string = getUniqueName("1container-with-dash"); + const containerClient = serviceClient.getFileSystemClient(containerName); + await containerClient.create(); + + try { + await containerClient.getAccessPolicy(); + } catch (err) { + assert.deepStrictEqual( + err.message.includes("Server failed to authenticate the request."), + true + ); + await containerClient.delete(); + return; + } + await containerClient.delete(); + assert.fail(); + }); + + it(`Should not work with set container ACL @loki @sql`, async () => { + const token = generateJWTToken( + new Date("2019/01/01"), + new Date("2019/01/01"), + new Date("2100/01/01"), + "https://sts.windows-ppe.net/ab1f708d-50f6-404c-a006-d71b2ac7a606/", + "https://devstoreaccount1.blob.core.windows.net", + "user_impersonation", + "23657296-5cd5-45b0-a809-d972a7f4dfe1", + "dd0d0df1-06c3-436c-8034-4b9a153097ce" + ); + + const serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline(new SimpleTokenCredential(token), { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + + const containerName: string = getUniqueName("1container-with-dash"); + const containerClient = serviceClient.getFileSystemClient(containerName); + await containerClient.create(); + + try { + await containerClient.setAccessPolicy("filesystem"); + } catch (err) { + assert.deepStrictEqual( + err.message.includes("Server failed to authenticate the request."), + true + ); + await containerClient.delete(); + return; + } + await containerClient.delete(); + assert.fail(); + }); + + it("Create container with not exist Account, return 404 @loki @sql", async () => { + const accountNameNotExist = "devstoreaccountnotexist"; + const baseURL = `https://${server.config.host}:${server.config.port}/${accountNameNotExist}`; + const containerName: string = getUniqueName("1container-with-dash"); + + // Shared key + const sharedKeyCredential = new StorageSharedKeyCredential( + accountNameNotExist, + EMULATOR_ACCOUNT_KEY + ); + let serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline(sharedKeyCredential, { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + let containerClientNotExist = + serviceClient.getFileSystemClient(containerName); + try { + await containerClientNotExist.create(); + } catch (err) { + if (err.statusCode !== 404 && err.code !== "ResourceNotFound") { + assert.fail( + "Create queue with shared key not fail as expected." + err.toString() + ); + } + } + + // Oauth + const token = generateJWTToken( + new Date("2019/01/01"), + new Date("2019/01/01"), + new Date("2100/01/01"), + "https://sts.windows-ppe.net/ab1f708d-50f6-404c-a006-d71b2ac7a606/", + "https://storage.azure.com", + "user_impersonation", + "23657296-5cd5-45b0-a809-d972a7f4dfe1", + "dd0d0df1-06c3-436c-8034-4b9a153097ce" + ); + + serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline(new SimpleTokenCredential(token), { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + containerClientNotExist = serviceClient.getFileSystemClient(containerName); + try { + await containerClientNotExist.create(); + } catch (err) { + if (err.statusCode !== 404 && err.code !== "ResourceNotFound") { + assert.fail( + "Create queue with oauth not fail as expected." + err.toString() + ); + } + } + // Account SAS + const now = new Date(); + now.setMinutes(now.getMinutes() - 5); + const tmr = new Date(); + tmr.setDate(tmr.getDate() + 1); + const sas = generateAccountSASQueryParameters( + { + expiresOn: tmr, + ipRange: { start: "0.0.0.0", end: "255.255.255.255" }, + permissions: AccountSASPermissions.parse("rwdlacup"), + protocol: SASProtocol.HttpsAndHttp, + resourceTypes: AccountSASResourceTypes.parse("sco").toString(), + services: AccountSASServices.parse("btqf").toString(), + startsOn: now, + version: "2016-05-31" + }, + sharedKeyCredential + ).toString(); + let sasURL = `${serviceClient.url}?${sas}`; + serviceClient = new DataLakeServiceClient( + sasURL, + newPipeline(new AnonymousCredential(), { + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + containerClientNotExist = serviceClient.getFileSystemClient(containerName); + try { + await containerClientNotExist.create(); + } catch (err) { + if (err.statusCode !== 404 && err.code !== "ResourceNotFound") { + assert.fail( + "Create queue with account sas not fail as expected." + err.toString() + ); + } + } + + // Service SAS + const containerSAS = generateDataLakeSASQueryParameters( + { + fileSystemName: containerName, + expiresOn: tmr, + ipRange: { start: "0.0.0.0", end: "255.255.255.255" }, + permissions: FileSystemSASPermissions.parse("racwdl"), + protocol: SASProtocol.HttpsAndHttp, + startsOn: now, + version: "2016-05-31" + }, + sharedKeyCredential + ); + sasURL = `${serviceClient.url}?${containerSAS}`; + serviceClient = new DataLakeServiceClient( + sasURL, + newPipeline(new AnonymousCredential(), { + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + containerClientNotExist = serviceClient.getFileSystemClient(containerName); + try { + await containerClientNotExist.create(); + } catch (err) { + if (err.statusCode !== 404 && err.code !== "ResourceNotFound") { + assert.fail( + "Create queue with service sas not fail as expected." + err.toString() + ); + } + } + }); + + it(`Should not work with HTTP @loki @sql`, async () => { + await server.close(); + await server.clean(); + + server = factory.createServer(false, false, false, "basic"); + await server.start(); + + const httpBaseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`; + + const token = generateJWTToken( + new Date("2019/01/01"), + new Date("2019/01/01"), + new Date("2019/01/01"), + "https://sts.windows-ppe.net/ab1f708d-50f6-404c-a006-d71b2ac7a606/", + "https://devstoreaccount1.blob.core.windows.net", + "user_impersonation", + "23657296-5cd5-45b0-a809-d972a7f4dfe1", + "dd0d0df1-06c3-436c-8034-4b9a153097ce" + ); + + const serviceClient = new DataLakeServiceClient( + httpBaseURL, + newPipeline(new SimpleTokenCredential(token), { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + + const containerName: string = getUniqueName("1container-with-dash"); + const containerClient = serviceClient.getFileSystemClient(containerName); + + try { + await containerClient.create(); + await containerClient.delete(); + } catch (err) { + assert.deepStrictEqual( + err.message.includes("Bearer token authentication is not permitted"), + true + ); + assert.deepStrictEqual(err.message.includes("non-https"), true); + return; + } + assert.fail(); + }); +}); diff --git a/tests/dfs/sas.test.ts b/tests/dfs/sas.test.ts new file mode 100644 index 000000000..87759606a --- /dev/null +++ b/tests/dfs/sas.test.ts @@ -0,0 +1,851 @@ +import * as assert from "assert"; +import { + AccountSASPermissions, + AccountSASResourceTypes, + AccountSASServices, + AnonymousCredential, + DataLakeFileClient, + DataLakeFileSystemClient, + DataLakeSASPermissions, + DataLakeServiceClient, + FileSystemSASPermissions, + generateAccountSASQueryParameters, + generateDataLakeSASQueryParameters, + newPipeline, + SASProtocol, + StorageSharedKeyCredential +} from "@azure/storage-file-datalake"; + +import { configLogger } from "../../src/common/Logger"; +import { + EMULATOR_ACCOUNT_KEY_STR, + EMULATOR_ACCOUNT_NAME +} from "../../src/dfs/utils/constants"; +import { getUniqueName } from "../testutils"; +import BlobTestServerFactory from "../BlobTestServerFactory"; + +const EMULATOR_ACCOUNT2_NAME = "devstoreaccount2"; +const EMULATOR_ACCOUNT2_KEY_STR = + "MTAwCjE2NQoyMjUKMTAzCjIxOAoyNDEKNDAKNzgKMTkxCjE3OAoyMTQKMTY5CjIxMwo2MQoyNTIKMTQxCg=="; + +// Set true to enable debug log +configLogger(false); + +describe("Shared Access Signature (SAS) authentication", () => { + // Setup two accounts for validating cross-account copy operations + process.env[ + "AZURITE_ACCOUNTS" + ] = `${EMULATOR_ACCOUNT_NAME}:${EMULATOR_ACCOUNT_KEY_STR};${EMULATOR_ACCOUNT2_NAME}:${EMULATOR_ACCOUNT2_KEY_STR}`; + + const factory = new BlobTestServerFactory(true); + const server = factory.createServer(); + + const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`; + const serviceClient = new DataLakeServiceClient( + baseURL, + newPipeline( + new StorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY_STR + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ) + ); + + before(async () => { + await server.start(); + }); + + after(async () => { + await server.close(); + await server.clean(); + }); + + it("generateAccountSASQueryParameters should work @loki @sql", async () => { + const now = new Date(); + now.setMinutes(now.getMinutes() - 5); // Skip clock skew with server + + const tmr = new Date(); + tmr.setDate(tmr.getDate() + 1); + + // By default, credential is always the last element of pipeline factories + const factories = (serviceClient as any).pipeline.factories; + const storageSharedKeyCredential = factories[factories.length - 1]; + + const sas = generateAccountSASQueryParameters( + { + expiresOn: tmr, + ipRange: { start: "0.0.0.0", end: "255.255.255.255" }, + permissions: AccountSASPermissions.parse("rwdlacup"), + protocol: SASProtocol.HttpsAndHttp, + resourceTypes: AccountSASResourceTypes.parse("sco").toString(), + services: AccountSASServices.parse("btqf").toString(), + startsOn: now, + version: "2016-05-31" + }, + storageSharedKeyCredential as StorageSharedKeyCredential + ).toString(); + + const sasURL = `${serviceClient.url}?${sas}`; + const serviceClientWithSAS = new DataLakeServiceClient( + sasURL, + newPipeline(new AnonymousCredential(), { + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + + await serviceClientWithSAS.getProperties(); + }); + + it("generateAccountSASQueryParameters should work for set blob tier @loki @sql", async () => { + const now = new Date(); + now.setMinutes(now.getMinutes() - 5); // Skip clock skew with server + + const tmr = new Date(); + tmr.setDate(tmr.getDate() + 1); + + // By default, credential is always the last element of pipeline factories + const factories = (serviceClient as any).pipeline.factories; + const storageSharedKeyCredential = factories[factories.length - 1]; + + const sas = generateAccountSASQueryParameters( + { + expiresOn: tmr, + ipRange: { start: "0.0.0.0", end: "255.255.255.255" }, + permissions: AccountSASPermissions.parse("w"), + protocol: SASProtocol.HttpsAndHttp, + resourceTypes: AccountSASResourceTypes.parse("sco").toString(), + services: AccountSASServices.parse("btqf").toString(), + startsOn: now, + version: "2016-05-31" + }, + storageSharedKeyCredential as StorageSharedKeyCredential + ).toString(); + + const sasURL = `${serviceClient.url}?${sas}`; + const serviceClientWithSAS = new DataLakeServiceClient( + sasURL, + newPipeline(new AnonymousCredential(), { + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + + const containerClientWithSAS = serviceClientWithSAS.getFileSystemClient( + getUniqueName("con") + ); + await containerClientWithSAS.create(); + + const blockBlobClientWithSAS = containerClientWithSAS.getFileClient( + getUniqueName("blob") + ); + await blockBlobClientWithSAS.upload(Buffer.from("abc")); + + //TODO: Revisit + // await blockBlobClientWithSAS.setAccessTier("Hot"); + }); + + it("generateAccountSASQueryParameters should not work with invalid permission @loki @sql", async () => { + const tmr = new Date(); + tmr.setDate(tmr.getDate() + 1); + + // By default, credential is always the last element of pipeline factories + const factories = (serviceClient as any).pipeline.factories; + const storageSharedKeyCredential = factories[factories.length - 1]; + + const sas = generateAccountSASQueryParameters( + { + expiresOn: tmr, + permissions: AccountSASPermissions.parse("wdlcup"), + resourceTypes: AccountSASResourceTypes.parse("sco").toString(), + services: AccountSASServices.parse("btqf").toString() + }, + storageSharedKeyCredential as StorageSharedKeyCredential + ).toString(); + + const sasURL = `${serviceClient.url}?${sas}`; + const serviceClientWithSAS = new DataLakeServiceClient( + sasURL, + newPipeline(new AnonymousCredential(), { + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + + let error; + try { + await serviceClientWithSAS.getProperties(); + } catch (err) { + error = err; + } + + assert.ok(error); + }); + + it("generateAccountSASQueryParameters should not work with invalid service @loki @sql", async () => { + const tmr = new Date(); + tmr.setDate(tmr.getDate() + 1); + + // By default, credential is always the last element of pipeline factories + const factories = (serviceClient as any).pipeline.factories; + const storageSharedKeyCredential = factories[factories.length - 1]; + + const sas = generateAccountSASQueryParameters( + { + expiresOn: tmr, + permissions: AccountSASPermissions.parse("rwdlacup"), + resourceTypes: AccountSASResourceTypes.parse("sco").toString(), + services: AccountSASServices.parse("tqf").toString() + }, + storageSharedKeyCredential as StorageSharedKeyCredential + ).toString(); + + const sasURL = `${serviceClient.url}?${sas}`; + const serviceClientWithSAS = new DataLakeServiceClient( + sasURL, + newPipeline(new AnonymousCredential(), { + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + + let error; + try { + await serviceClientWithSAS.getProperties(); + } catch (err) { + error = err; + } + + assert.ok(error); + }); + + it("generateAccountSASQueryParameters should not work with invalid resource type @loki @sql", async () => { + const tmr = new Date(); + tmr.setDate(tmr.getDate() + 1); + + // By default, credential is always the last element of pipeline factories + const factories = (serviceClient as any).pipeline.factories; + const storageSharedKeyCredential = factories[factories.length - 1]; + + const sas = generateAccountSASQueryParameters( + { + expiresOn: tmr, + ipRange: { start: "0.0.0.0", end: "255.255.255.255" }, + permissions: AccountSASPermissions.parse("rwdlacup"), + protocol: SASProtocol.HttpsAndHttp, + resourceTypes: AccountSASResourceTypes.parse("co").toString(), + services: AccountSASServices.parse("btqf").toString(), + version: "2016-05-31" + }, + storageSharedKeyCredential as StorageSharedKeyCredential + ).toString(); + + const sasURL = `${serviceClient.url}?${sas}`; + const serviceClientWithSAS = new DataLakeServiceClient( + sasURL, + newPipeline(new AnonymousCredential(), { + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + + let error; + try { + await serviceClientWithSAS.getProperties(); + } catch (err) { + error = err; + } + + assert.ok(error); + }); + + it("Upload/Create/Append should work with write permission in account SAS to override an existing blob", async () => { + const tmr = new Date(); + tmr.setDate(tmr.getDate() + 1); + + // By default, credential is always the last element of pipeline factories + const factories = (serviceClient as any).pipeline.factories; + const storageSharedKeyCredential = factories[factories.length - 1]; + + const sas = generateAccountSASQueryParameters( + { + expiresOn: tmr, + ipRange: { start: "0.0.0.0", end: "255.255.255.255" }, + permissions: AccountSASPermissions.parse("rwdlacup"), + protocol: SASProtocol.HttpsAndHttp, + resourceTypes: AccountSASResourceTypes.parse("co").toString(), + services: AccountSASServices.parse("btqf").toString(), + version: "2016-05-31" + }, + storageSharedKeyCredential as StorageSharedKeyCredential + ).toString(); + + // const sasURL = `http://${productionStyleHostName}:${server.config.port}?${sas}`; + const sasURL = `${serviceClient.url}/?${sas}`; + const serviceClientWithSAS = new DataLakeServiceClient( + sasURL, + newPipeline(new AnonymousCredential(), { + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + + const fileSystemName = getUniqueName("con"); + const containerClient = + serviceClientWithSAS.getFileSystemClient(fileSystemName); + await containerClient.create(); + + const blobName1 = getUniqueName("blob"); + const blob1 = containerClient.getFileClient(blobName1); + + await blob1.upload(Buffer.from("hello")); + const buffer = await blob1.readToBuffer(); + assert.deepStrictEqual(buffer, Buffer.from("hello")); + }); + + it("Upload/Create/Append shouldn't work without write permission in account SAS to override an existing blob @loki @sql", async () => { + const tmr = new Date(); + tmr.setDate(tmr.getDate() + 1); + + // By default, credential is always the last element of pipeline factories + const factories = (serviceClient as any).pipeline.factories; + const storageSharedKeyCredential = factories[factories.length - 1]; + + const sas = generateAccountSASQueryParameters( + { + expiresOn: tmr, + ipRange: { start: "0.0.0.0", end: "255.255.255.255" }, + permissions: AccountSASPermissions.parse("rdlacup"), + protocol: SASProtocol.HttpsAndHttp, + resourceTypes: AccountSASResourceTypes.parse("co").toString(), + services: AccountSASServices.parse("btqf").toString(), + version: "2016-05-31" + }, + storageSharedKeyCredential as StorageSharedKeyCredential + ).toString(); + + const sasURL = `${serviceClient.url}?${sas}`; + const serviceClientWithSAS = new DataLakeServiceClient( + sasURL, + newPipeline(new AnonymousCredential(), { + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + + const fileSystemName = getUniqueName("con"); + const containerClient = + serviceClientWithSAS.getFileSystemClient(fileSystemName); + await containerClient.create(); + + const blobName1 = getUniqueName("blob"); + const blob1 = containerClient.getFileClient(blobName1); + + // this copy should throw 403 error + let error; + try { + await blob1.upload(Buffer.from("hello")); + } catch (err) { + error = err; + } + assert.deepEqual(error.statusCode, 403); + assert.ok(error !== undefined); + }); + + it("Create blob should work without write permission in account SAS to an nonexisting blob @loki @sql", async () => { + const tmr = new Date(); + tmr.setDate(tmr.getDate() + 1); + + // By default, credential is always the last element of pipeline factories + const factories = (serviceClient as any).pipeline.factories; + const storageSharedKeyCredential = factories[factories.length - 1]; + + const sas = generateAccountSASQueryParameters( + { + expiresOn: tmr, + ipRange: { start: "0.0.0.0", end: "255.255.255.255" }, + permissions: AccountSASPermissions.parse("c"), + protocol: SASProtocol.HttpsAndHttp, + resourceTypes: AccountSASResourceTypes.parse("co").toString(), + services: AccountSASServices.parse("btqf").toString(), + version: "2016-05-31" + }, + storageSharedKeyCredential as StorageSharedKeyCredential + ).toString(); + + const sasURL = `${serviceClient.url}?${sas}`; + const serviceClientWithSAS = new DataLakeServiceClient( + sasURL, + newPipeline(new AnonymousCredential(), { + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + + const fileSystemName = getUniqueName("con"); + const containerClient = + serviceClientWithSAS.getFileSystemClient(fileSystemName); + await containerClient.create(); + + const blobName1 = getUniqueName("blob"); + const blob1 = containerClient.getFileClient(blobName1); + await blob1.create(); + }); + + it("Upload/Create/Append blob should work with write permission in account SAS to override an existing blob @loki @sql", async () => { + const tmr = new Date(); + tmr.setDate(tmr.getDate() + 1); + + // By default, credential is always the last element of pipeline factories + const factories = (serviceClient as any).pipeline.factories; + const storageSharedKeyCredential = factories[factories.length - 1]; + + const sas = generateAccountSASQueryParameters( + { + expiresOn: tmr, + ipRange: { start: "0.0.0.0", end: "255.255.255.255" }, + permissions: AccountSASPermissions.parse("rwdlacup"), + protocol: SASProtocol.HttpsAndHttp, + resourceTypes: AccountSASResourceTypes.parse("co").toString(), + services: AccountSASServices.parse("btqf").toString(), + version: "2016-05-31" + }, + storageSharedKeyCredential as StorageSharedKeyCredential + ).toString(); + + const sasURL = `${serviceClient.url}?${sas}`; + const serviceClientWithSAS = new DataLakeServiceClient( + sasURL, + newPipeline(new AnonymousCredential(), { + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + }) + ); + + const fileSystemName = getUniqueName("con"); + const containerClient = + serviceClientWithSAS.getFileSystemClient(fileSystemName); + await containerClient.create(); + + const blobName1 = getUniqueName("blob"); + const blobName2 = getUniqueName("blob"); + const blob1 = containerClient.getFileClient(blobName1); + const blob2 = containerClient.getFileClient(blobName2); + + await blob1.upload(Buffer.from("hello")); + // this copy should not throw any errors + await blob2.create(); + await blob2.append("hello", 0, 5, { flush: true }); + }); + + it("generateDataLakeSASQueryParameters should work for container @loki @sql", async () => { + const now = new Date(); + now.setMinutes(now.getMinutes() - 5); // Skip clock skew with server + + const tmr = new Date(); + tmr.setDate(tmr.getDate() + 1); + + // By default, credential is always the last element of pipeline factories + const factories = (serviceClient as any).pipeline.factories; + const storageSharedKeyCredential = factories[factories.length - 1]; + + const fileSystemName = getUniqueName("container"); + const containerClient = serviceClient.getFileSystemClient(fileSystemName); + await containerClient.create(); + + const containerSAS = generateDataLakeSASQueryParameters( + { + fileSystemName, + expiresOn: tmr, + ipRange: { start: "0.0.0.0", end: "255.255.255.255" }, + permissions: FileSystemSASPermissions.parse("racwdl"), + protocol: SASProtocol.HttpsAndHttp, + startsOn: now, + version: "2016-05-31" + }, + storageSharedKeyCredential as StorageSharedKeyCredential + ); + + const sasURL = `${containerClient.url}?${containerSAS}`; + const containerClientWithSAS = new DataLakeFileSystemClient( + sasURL, + newPipeline(new AnonymousCredential()) + ); + + await containerClientWithSAS.listPaths().byPage().next(); + await containerClient.delete(); + }); + + it("generateDataLakeSASQueryParameters should work for append blob with original headers @loki @sql", async () => { + const now = new Date(); + now.setMinutes(now.getMinutes() - 5); // Skip clock skew with server + + const tmr = new Date(); + tmr.setDate(tmr.getDate() + 1); + + // By default, credential is always the last element of pipeline factories + const factories = (serviceClient as any).pipeline.factories; + const storageSharedKeyCredential = factories[factories.length - 1]; + + const fileSystemName = getUniqueName("container"); + const containerClient = serviceClient.getFileSystemClient(fileSystemName); + await containerClient.create(); + + const blobName = getUniqueName("blob"); + const blobClient = containerClient.getFileClient(blobName); + await blobClient.create({ + pathHttpHeaders: { + cacheControl: "cache-control-original", + contentType: "content-type-original", + contentDisposition: "content-disposition-original", + contentEncoding: "content-encoding-original", + contentLanguage: "content-language-original" + } + }); + + const blobSAS = generateDataLakeSASQueryParameters( + { + pathName: blobName, + fileSystemName, + expiresOn: tmr, + ipRange: { start: "0.0.0.0", end: "255.255.255.255" }, + permissions: DataLakeSASPermissions.parse("racwd"), + protocol: SASProtocol.HttpsAndHttp, + startsOn: now, + version: "2016-05-31" + }, + storageSharedKeyCredential as StorageSharedKeyCredential + ); + + const sasURL = `${blobClient.url}?${blobSAS}`; + const blobClientWithSAS = new DataLakeFileClient( + sasURL, + newPipeline(new AnonymousCredential()) + ); + + await blobClientWithSAS.getProperties(); + + const properties = await blobClientWithSAS.getProperties(); + assert.equal(properties.cacheControl, "cache-control-original"); + assert.equal(properties.contentDisposition, "content-disposition-original"); + assert.equal(properties.contentEncoding, "content-encoding-original"); + assert.equal(properties.contentLanguage, "content-language-original"); + assert.equal(properties.contentType, "content-type-original"); + + const downloadResponse = await blobClientWithSAS.read(); + assert.equal(downloadResponse.cacheControl, "cache-control-original"); + assert.equal( + downloadResponse.contentDisposition, + "content-disposition-original" + ); + assert.equal(downloadResponse.contentEncoding, "content-encoding-original"); + assert.equal(downloadResponse.contentLanguage, "content-language-original"); + assert.equal(downloadResponse.contentType, "content-type-original"); + + await containerClient.delete(); + }); + + it("generateDataLakeSASQueryParameters should work for append blob and override headers @loki @sql", async () => { + const now = new Date(); + now.setMinutes(now.getMinutes() - 5); // Skip clock skew with server + + const tmr = new Date(); + tmr.setDate(tmr.getDate() + 1); + + // By default, credential is always the last element of pipeline factories + const factories = (serviceClient as any).pipeline.factories; + const storageSharedKeyCredential = factories[factories.length - 1]; + + const fileSystemName = getUniqueName("container"); + const containerClient = serviceClient.getFileSystemClient(fileSystemName); + await containerClient.create(); + + const blobName = getUniqueName("blob"); + const blobClient = containerClient.getFileClient(blobName); + await blobClient.create({ + pathHttpHeaders: { + contentType: "content-type-original" + } + }); + + const blobSAS = generateDataLakeSASQueryParameters( + { + pathName: blobName, + cacheControl: "cache-control-override", + fileSystemName, + contentDisposition: "content-disposition-override", + contentEncoding: "content-encoding-override", + contentLanguage: "content-language-override", + contentType: "content-type-override", + expiresOn: tmr, + ipRange: { start: "0.0.0.0", end: "255.255.255.255" }, + permissions: DataLakeSASPermissions.parse("racwd"), + protocol: SASProtocol.HttpsAndHttp, + startsOn: now, + version: "2016-05-31" + }, + storageSharedKeyCredential as StorageSharedKeyCredential + ); + + const sasURL = `${blobClient.url}?${blobSAS}`; + const blobClientWithSAS = new DataLakeFileClient( + sasURL, + newPipeline(new AnonymousCredential()) + ); + + await blobClientWithSAS.getProperties(); + + const properties = await blobClientWithSAS.getProperties(); + assert.equal(properties.cacheControl, "cache-control-override"); + assert.equal(properties.contentDisposition, "content-disposition-override"); + assert.equal(properties.contentEncoding, "content-encoding-override"); + assert.equal(properties.contentLanguage, "content-language-override"); + assert.equal(properties.contentType, "content-type-override"); + + const downloadResponse = await blobClientWithSAS.read(); + assert.equal(downloadResponse.cacheControl, "cache-control-override"); + assert.equal( + downloadResponse.contentDisposition, + "content-disposition-override" + ); + assert.equal(downloadResponse.contentEncoding, "content-encoding-override"); + assert.equal(downloadResponse.contentLanguage, "content-language-override"); + assert.equal(downloadResponse.contentType, "content-type-override"); + + await containerClient.delete(); + }); + + it("generateDataLakeSASQueryParameters should work for blob with special naming @loki @sql", async () => { + const now = new Date(); + now.setMinutes(now.getMinutes() - 5); // Skip clock skew with server + + const tmr = new Date(); + tmr.setDate(tmr.getDate() + 1); + + // By default, credential is always the last element of pipeline factories + const factories = (serviceClient as any).pipeline.factories; + const storageSharedKeyCredential = factories[factories.length - 1]; + + const fileSystemName = getUniqueName("container-with-dash"); + const containerClient = serviceClient.getFileSystemClient(fileSystemName); + await containerClient.create(); + + const blobName = getUniqueName( + // tslint:disable-next-line:max-line-length + "////Upper/blob/empty /another 汉字 ру́сский язы́к ру́сский язы́к عربي/عربى にっぽんご/にほんご . special ~!@#$%^&*()_+`1234567890-={}|[]\\:\";'<>?,/'" + ); + const blobClient = containerClient.getFileClient(blobName); + await blobClient.create({ + pathHttpHeaders: { + contentType: "content-type-original" + } + }); + + const blobSAS = generateDataLakeSASQueryParameters( + { + // NOTICE: Azure Storage Server will replace "\" with "/" in the blob names + pathName: blobName.replace(/\\/g, "/"), + cacheControl: "cache-control-override", + fileSystemName, + contentDisposition: "content-disposition-override", + contentEncoding: "content-encoding-override", + contentLanguage: "content-language-override", + contentType: "content-type-override", + expiresOn: tmr, + ipRange: { start: "0.0.0.0", end: "255.255.255.255" }, + permissions: DataLakeSASPermissions.parse("racwd"), + protocol: SASProtocol.HttpsAndHttp, + startsOn: now, + version: "2016-05-31" + }, + storageSharedKeyCredential as StorageSharedKeyCredential + ); + + const sasURL = `${blobClient.url}?${blobSAS}`; + const blobClientWithSAS = new DataLakeFileClient( + sasURL, + newPipeline(new AnonymousCredential()) + ); + + await blobClientWithSAS.getProperties(); + + const properties = await blobClientWithSAS.getProperties(); + assert.equal(properties.cacheControl, "cache-control-override"); + assert.equal(properties.contentDisposition, "content-disposition-override"); + assert.equal(properties.contentEncoding, "content-encoding-override"); + assert.equal(properties.contentLanguage, "content-language-override"); + assert.equal(properties.contentType, "content-type-override"); + + const downloadResponse = await blobClientWithSAS.read(); + assert.equal(downloadResponse.cacheControl, "cache-control-override"); + assert.equal( + downloadResponse.contentDisposition, + "content-disposition-override" + ); + assert.equal(downloadResponse.contentEncoding, "content-encoding-override"); + assert.equal(downloadResponse.contentLanguage, "content-language-override"); + assert.equal(downloadResponse.contentType, "content-type-override"); + + await containerClient.delete(); + }); + + it("generateDataLakeSASQueryParameters should work for blob with access policy @loki @sql", async () => { + const now = new Date(); + now.setMinutes(now.getMinutes() - 5); // Skip clock skew with server + + const tmr = new Date(); + tmr.setDate(tmr.getDate() + 1); + + // By default, credential is always the last element of pipeline factories + const factories = (serviceClient as any).pipeline.factories; + const storageSharedKeyCredential = factories[factories.length - 1]; + + const fileSystemName = getUniqueName("container"); + const containerClient = serviceClient.getFileSystemClient(fileSystemName); + await containerClient.create(); + + const blobName = getUniqueName("blob"); + const blobClient = containerClient.getFileClient(blobName); + await blobClient.create(); + + const id = "unique-id"; + const result = await containerClient.setAccessPolicy(undefined, [ + { + accessPolicy: { + expiresOn: tmr, + permissions: FileSystemSASPermissions.parse("racwdl").toString(), + startsOn: now + }, + id + } + ]); + assert.equal( + result._response.request.headers.get("x-ms-client-request-id"), + result.clientRequestId + ); + + const blobSAS = generateDataLakeSASQueryParameters( + { + fileSystemName, + identifier: id + }, + storageSharedKeyCredential as StorageSharedKeyCredential + ); + + const sasURL = `${blobClient.url}?${blobSAS}`; + const blobClientWithSAS = new DataLakeFileClient( + sasURL, + newPipeline(new AnonymousCredential()) + ); + + await blobClientWithSAS.getProperties(); + await containerClient.delete(); + }); + + it("Synchronized copy blob should work with write permission in blob SAS to override an existing blob @loki @sql", async () => { + const now = new Date(); + now.setMinutes(now.getMinutes() - 5); // Skip clock skew with server + + const tmr = new Date(); + tmr.setDate(tmr.getDate() + 1); + + // By default, credential is always the last element of pipeline factories + const factories = (serviceClient as any).pipeline.factories; + const storageSharedKeyCredential = factories[factories.length - 1]; + + const fileSystemName = getUniqueName("container"); + const containerClient = serviceClient.getFileSystemClient(fileSystemName); + await containerClient.create(); + + const containerSAS = generateDataLakeSASQueryParameters( + { + fileSystemName, + expiresOn: tmr, + ipRange: { start: "0.0.0.0", end: "255.255.255.255" }, + permissions: FileSystemSASPermissions.parse("w"), + protocol: SASProtocol.HttpsAndHttp, + startsOn: now, + version: "2016-05-31" + }, + storageSharedKeyCredential as StorageSharedKeyCredential + ); + + const sasURL = `${containerClient.url}?${containerSAS}`; + const containerClientWithSAS = new DataLakeFileSystemClient( + sasURL, + newPipeline(new AnonymousCredential()) + ); + + const blobName1 = getUniqueName("blob"); + const blobName2 = getUniqueName("blob"); + const blob1 = containerClient.getFileClient(blobName1); + const blob2 = containerClient.getFileClient(blobName2); + const blob1SAS = containerClientWithSAS.getFileClient(blobName1); + + await blob1.create(); + await blob2.create(); + + await blob1SAS.create(); + await blob1SAS.append("hello", 0, 5, { flush: true }); + }); + + it("Synchronized copy blob shouldn't work without write permission in blob SAS to override an existing blob @loki @sql", async () => { + const now = new Date(); + now.setMinutes(now.getMinutes() - 5); // Skip clock skew with server + + const tmr = new Date(); + tmr.setDate(tmr.getDate() + 1); + + // By default, credential is always the last element of pipeline factories + const factories = (serviceClient as any).pipeline.factories; + const storageSharedKeyCredential = factories[factories.length - 1]; + + const fileSystemName = getUniqueName("container"); + const containerClient = serviceClient.getFileSystemClient(fileSystemName); + await containerClient.create(); + + const containerSAS = generateDataLakeSASQueryParameters( + { + fileSystemName, + expiresOn: tmr, + ipRange: { start: "0.0.0.0", end: "255.255.255.255" }, + permissions: FileSystemSASPermissions.parse("c"), + protocol: SASProtocol.HttpsAndHttp, + startsOn: now, + version: "2016-05-31" + }, + storageSharedKeyCredential as StorageSharedKeyCredential + ); + + const sasURL = `${containerClient.url}?${containerSAS}`; + const containerClientWithSAS = new DataLakeFileSystemClient( + sasURL, + newPipeline(new AnonymousCredential()) + ); + + const blobName1 = getUniqueName("blob"); + const blobName2 = getUniqueName("blob"); + const blob1 = containerClient.getFileClient(blobName1); + const blob2 = containerClient.getFileClient(blobName2); + const blob1SAS = containerClientWithSAS.getFileClient(blobName1); + + await blob1.upload(Buffer.from("hello")); + await blob2.upload(Buffer.from("world")); + + // this copy should throw 403 error + let error; + try { + await blob1SAS.create(); + await blob1SAS.append("hello", 0, 5, { flush: true }); + } catch (err) { + error = err; + } + assert.deepEqual(error.statusCode, 403); + assert.ok(error !== undefined); + }); +}); diff --git a/tests/exe.test.ts b/tests/exe.test.ts index e1e70387b..89c25c100 100644 --- a/tests/exe.test.ts +++ b/tests/exe.test.ts @@ -15,6 +15,11 @@ import { QueueServiceClient, StorageSharedKeyCredential as queueStorageSharedKeyCredential } from "@azure/storage-queue"; +import { + DataLakeServiceClient, + newPipeline as datalakeNewPipeline, + StorageSharedKeyCredential as datalakeStorageSharedKeyCredential +} from "@azure/storage-file-datalake"; import { configLogger } from "../src/common/Logger"; import { @@ -43,6 +48,7 @@ import { const blobAddress = "http://127.0.0.1:11000"; const queueAddress = "http://127.0.0.1:11001"; const tableAddress = "http://127.0.0.1:11002"; +const datalakeAddress = "http://127.0.0.1:11003"; // Set true to enable debug log configLogger(false); @@ -70,7 +76,12 @@ describe("exe test", () => { tableName = getUniqueName("table"); const child = execFile( ".\\release\\azurite.exe", - ["--blobPort 11000", "--queuePort 11001", "--tablePort 11002"], + [ + "--blobPort 11000", + "--queuePort 11001", + "--tablePort 11002", + "--datalakePort 11003" + ], { cwd: process.cwd(), shell: true, env: {} } ); @@ -89,6 +100,10 @@ describe("exe test", () => { tableAddress + "\nAzurite Table service is successfully listening at " + tableAddress + + "\nAzurite DataLake service is starting at " + + datalakeAddress + + "\nAzurite DataLake service is successfully listening at " + + datalakeAddress + "\n"; let messageReceived: string = ""; @@ -305,6 +320,82 @@ describe("exe test", () => { }); }); + describe("datalake test", () => { + const factory = new BlobTestServerFactory(true); + const datalakeServer = factory.createServer(); + + const datalakeBaseURL = `http://${datalakeServer.config.host}:${datalakeServer.config.port}/devstoreaccount1`; + const datalakeServiceClient = new DataLakeServiceClient( + datalakeBaseURL, + datalakeNewPipeline( + new datalakeStorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ) + ); + + let filesystemName: string = getUniqueName("filesystem"); + let filesystemClient = + datalakeServiceClient.getFileSystemClient(filesystemName); + let fileName: string = getUniqueName("file"); + let fileClient = filesystemClient.getFileClient(fileName); + const content = "Hello World"; + + beforeEach(async () => { + filesystemName = getUniqueName("filesystem"); + filesystemClient = + datalakeServiceClient.getFileSystemClient(filesystemName); + await filesystemClient.create(); + fileName = getUniqueName("file"); + fileClient = filesystemClient.getFileClient(fileName); + await fileClient.create(); + await fileClient.append(content, 0, content.length, { flush: true }); + }); + + afterEach(async () => { + await filesystemClient.delete(); + }); + it("download with with default parameters @loki @sql", async () => { + const result = await fileClient.read(); + assert.deepStrictEqual( + await bodyToString(result, content.length), + content + ); + assert.equal(result.contentRange, undefined); + assert.equal( + result._response.request.headers.get("x-ms-client-request-id"), + result.clientRequestId + ); + }); + + it("download should work with conditional headers @loki @sql", async () => { + const properties = await fileClient.getProperties(); + const result = await fileClient.read(0, undefined, { + conditions: { + ifMatch: properties.etag, + ifNoneMatch: "invalidetag", + ifModifiedSince: new Date("2018/01/01"), + ifUnmodifiedSince: new Date("2188/01/01") + } + }); + assert.deepStrictEqual( + await bodyToString(result, content.length), + content + ); + assert.equal(result.contentRange, undefined); + assert.equal( + result._response.request.headers.get("x-ms-client-request-id"), + result.clientRequestId + ); + }); + }); + describe("queue test", () => { // TODO: Create a server factory as tests utils const host = "127.0.0.1"; diff --git a/tests/linuxbinary.test.ts b/tests/linuxbinary.test.ts index 4a888f27a..de07f47d2 100644 --- a/tests/linuxbinary.test.ts +++ b/tests/linuxbinary.test.ts @@ -8,6 +8,11 @@ import { BlobServiceClient, newPipeline as blobNewPipeline, StorageSharedKeyCredential as blobStorageSharedKeyCredential } from '@azure/storage-blob'; +import { + DataLakeServiceClient, + newPipeline as datalakeNewPipeline, + StorageSharedKeyCredential as datalakeStorageSharedKeyCredential +} from "@azure/storage-file-datalake"; import { newPipeline as queueNewPipeline, QueueClient, QueueServiceClient, StorageSharedKeyCredential as queueStorageSharedKeyCredential @@ -30,6 +35,7 @@ import { const blobAddress = "http://127.0.0.1:11000"; const queueAddress = "http://127.0.0.1:11001"; const tableAddress = "http://127.0.0.1:11002"; +const datalakeAddress = "http://127.0.0.1:11003"; // Set true to enable debug log configLogger(false); @@ -56,13 +62,14 @@ describe("linux binary test", () => { before(async () => { overrideRequest(requestOverride, tableService); tableName = getUniqueName("table"); - const child = execFile("./release/azuritelinux", ["--blobPort 11000", "--queuePort 11001", "--tablePort 11002"], { cwd: process.cwd(), shell: true, env: {} }); + const child = execFile("./release/azuritelinux", ["--blobPort 11000", "--queuePort 11001", "--tablePort 11002", "--datalakePort 11003"], { cwd: process.cwd(), shell: true, env: {} }); childPid = child.pid; const fullSuccessMessage = "Azurite Blob service is starting at " + blobAddress + "\nAzurite Blob service is successfully listening at " + blobAddress + "\nAzurite Queue service is starting at " + queueAddress + "\nAzurite Queue service is successfully listening at " + queueAddress + - "\nAzurite Table service is starting at " + tableAddress + "\nAzurite Table service is successfully listening at " + tableAddress + "\n"; + "\nAzurite Table service is starting at " + tableAddress + "\nAzurite Table service is successfully listening at " + tableAddress + + "\nAzurite DataLake service is starting at " + datalakeAddress + "\nAzurite DataLake service is successfully listening at " + datalakeAddress + "\n"; let messageReceived: string = ""; function stdoutOn() { @@ -257,7 +264,84 @@ describe("linux binary test", () => { ifUnmodifiedSince: new Date("2188/01/01") } }); - assert.deepStrictEqual(await bodyToString(result, content.length), content); + assert.deepStrictEqual(await bodyToString(result, result.contentLength), content); + assert.equal(result.contentRange, undefined); + assert.equal( + result._response.request.headers.get("x-ms-client-request-id"), + result.clientRequestId + ); + }); + }); + + describe("datalake test", () => { + const factory = new BlobTestServerFactory(true); + const datalakeServer = factory.createServer(); + + const datalakeBaseURL = `http://${datalakeServer.config.host}:${datalakeServer.config.port}/devstoreaccount1`; + const datalakeServiceClient = new DataLakeServiceClient( + datalakeBaseURL, + datalakeNewPipeline( + new datalakeStorageSharedKeyCredential( + EMULATOR_ACCOUNT_NAME, + EMULATOR_ACCOUNT_KEY + ), + { + retryOptions: { maxTries: 1 }, + // Make sure socket is closed once the operation is done. + keepAliveOptions: { enable: false } + } + ) + ); + + let filesystemName: string = getUniqueName("filesystem"); + let filesystemClient = + datalakeServiceClient.getFileSystemClient(filesystemName); + let fileName: string = getUniqueName("file"); + let fileClient = filesystemClient.getFileClient(fileName); + const content = "Hello World"; + + beforeEach(async () => { + filesystemName = getUniqueName("filesystem"); + filesystemClient = + datalakeServiceClient.getFileSystemClient(filesystemName); + await filesystemClient.create(); + fileName = getUniqueName("file"); + fileClient = filesystemClient.getFileClient(fileName); + await fileClient.create(); + await fileClient.append(content, 0, content.length, { flush: true }); + }); + + afterEach(async () => { + await filesystemClient.delete(); + }); + + it("download with with default parameters @loki @sql", async () => { + const result = await fileClient.read(); + assert.deepStrictEqual( + await bodyToString(result, content.length), + content + ); + assert.equal(result.contentRange, undefined); + assert.equal( + result._response.request.headers.get("x-ms-client-request-id"), + result.clientRequestId + ); + }); + + it("download should work with conditional headers @loki @sql", async () => { + const properties = await fileClient.getProperties(); + const result = await fileClient.read(0, undefined, { + conditions: { + ifMatch: properties.etag, + ifNoneMatch: "invalidetag", + ifModifiedSince: new Date("2018/01/01"), + ifUnmodifiedSince: new Date("2188/01/01") + } + }); + assert.deepStrictEqual( + await bodyToString(result, content.length), + content + ); assert.equal(result.contentRange, undefined); assert.equal( result._response.request.headers.get("x-ms-client-request-id"), diff --git a/tests/testutils.ts b/tests/testutils.ts index 560d7b39a..c5d85329e 100644 --- a/tests/testutils.ts +++ b/tests/testutils.ts @@ -1,3 +1,10 @@ +import { isTokenCredential } from "@azure/core-auth"; +import { + CpkInfo, + DataLakeFileClient, + DataLakeFileSystemClient +} from "@azure/storage-file-datalake"; +import assert from "assert"; import { StorageServiceClient } from "azure-storage"; import { randomBytes } from "crypto"; import { createWriteStream, readFileSync } from "fs"; @@ -81,6 +88,10 @@ export async function bodyToString( return ""; } + if (length === undefined) { + length = response.contentLength; + } + return new Promise((resolve, reject) => { response.readableStreamBody!.on("readable", () => { let chunk; @@ -145,7 +156,7 @@ export async function createRandomLocalFile( ws.on("open", () => { // tslint:disable-next-line:no-empty - while (offsetInMB++ < blockNumber && ws.write(randomValueHex())) {} + while (offsetInMB++ < blockNumber && ws.write(randomValueHex())) { /**/ } if (offsetInMB >= blockNumber) { ws.end(); } @@ -153,7 +164,7 @@ export async function createRandomLocalFile( ws.on("drain", () => { // tslint:disable-next-line:no-empty - while (offsetInMB++ < blockNumber && ws.write(randomValueHex())) {} + while (offsetInMB++ < blockNumber && ws.write(randomValueHex())) { /**/ } if (offsetInMB >= blockNumber) { ws.end(); } @@ -251,3 +262,43 @@ export function overrideRequest( ); }; } + +export function getEncryptionScope(): string { + // return "ENCRYPTION_SCOPE"; + throw new Error("encryption scope not implemented yet."); +} + +export function getYieldedValue( + iteratorResult: IteratorResult +): YT { + if (iteratorResult.done) { + assert.fail(`Expected an item but did not get any`); + } + return iteratorResult.value; +} + +export const Test_CPK_INFO: CpkInfo = { + encryptionKey: "MDEyMzQ1NjcwMTIzNDU2NzAxMjM0NTY3MDEyMzQ1Njc=", // [SuppressMessage("Microsoft.Security", "CS001:SecretInline", Justification="This is a fake secret")] + encryptionKeySha256: "3QFFFpRA5+XANHqwwbT4yXDmrT/2JaLt/FKHjzhOdoE=" // [SuppressMessage("Microsoft.Security", "CS001:SecretInline", Justification="This is a fake secret")] +}; + +export function assertClientUsesTokenCredential( + client: DataLakeFileSystemClient +): void { + assert.ok(isTokenCredential(client.credential)); +} + +export async function upload( + fileClient: DataLakeFileClient, + data: string, + metadata: any = undefined +) { + let uploadResult = await (metadata + ? fileClient.create(metadata) + : fileClient.create()); + assert.ok(uploadResult.requestId); + uploadResult = await fileClient.append(data, 0, data.length); + assert.ok(uploadResult.requestId); + uploadResult = await fileClient.flush(data.length); + assert.ok(uploadResult.requestId); +}