From fc147dc0c5f87536550c0c0f4c54cb5c1d16bc1c Mon Sep 17 00:00:00 2001 From: Andrew Gaul Date: Wed, 20 Sep 2017 20:45:00 -0700 Subject: [PATCH] JCLOUDS-1335: Azure Blob object access tiers --- .../jclouds/azureblob/AzureBlobClient.java | 10 +++++ .../jclouds/azureblob/domain/AccessTier.java | 40 +++++++++++++++++++ .../azureblob/domain/BlobProperties.java | 3 ++ .../domain/MutableBlobProperties.java | 2 + .../domain/internal/BlobPropertiesImpl.java | 18 ++++++++- .../internal/MutableBlobPropertiesImpl.java | 14 +++++++ .../ParseBlobPropertiesFromHeaders.java | 5 +++ ...ontainerNameEnumerationResultsHandler.java | 7 +++- .../azureblob/AzureBlobClientLiveTest.java | 34 +++++++++++++++- .../azureblob/AzureBlobClientTest.java | 18 +++++++++ ...inerNameEnumerationResultsHandlerTest.java | 9 +++-- .../src/test/resources/test_list_blobs.xml | 3 ++ .../resources/test_list_blobs_options.xml | 1 + 13 files changed, 157 insertions(+), 7 deletions(-) create mode 100644 providers/azureblob/src/main/java/org/jclouds/azureblob/domain/AccessTier.java diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobClient.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobClient.java index a50cf8ea87..32da1de01f 100644 --- a/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobClient.java +++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobClient.java @@ -27,6 +27,7 @@ import javax.inject.Named; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.HEAD; +import javax.ws.rs.HeaderParam; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; @@ -45,6 +46,7 @@ import org.jclouds.azureblob.binders.BindAzureBlocksToRequest; import org.jclouds.azureblob.binders.BindAzureContentMetadataToRequest; import org.jclouds.azureblob.binders.BindAzureCopyOptionsToRequest; import org.jclouds.azureblob.binders.BindPublicAccessToRequest; +import org.jclouds.azureblob.domain.AccessTier; import org.jclouds.azureblob.domain.AzureBlob; import org.jclouds.azureblob.domain.BlobProperties; import org.jclouds.azureblob.domain.ContainerProperties; @@ -434,6 +436,14 @@ public interface AzureBlobClient extends Closeable { @PathParam("container") @ParamValidators(ContainerNameValidator.class) String container, @PathParam("name") String name, @BinderParam(BindMapToHeadersWithPrefix.class) Map metadata); + @Named("SetAccessTier") + @PUT + @Path("{container}/{name}") + @QueryParams(keys = { "comp" }, values = { "tier" }) + void setBlobTier( + @PathParam("container") @ParamValidators(ContainerNameValidator.class) String container, + @PathParam("name") String name, @HeaderParam("x-ms-access-tier") AccessTier tier); + /** * The Delete Blob operation marks the specified blob for deletion. The blob is later deleted * during garbage collection. diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/AccessTier.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/AccessTier.java new file mode 100644 index 0000000000..02f03ca4f1 --- /dev/null +++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/AccessTier.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.azureblob.domain; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.base.CaseFormat; + +public enum AccessTier { + HOT, + COOL, + ARCHIVE; + + public String value() { + return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name()); + } + + @Override + public String toString() { + return value(); + } + + public static AccessTier fromValue(String tier) { + return valueOf(CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, checkNotNull(tier, "tier"))); + } +} diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/BlobProperties.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/BlobProperties.java index f267b4461b..f58987ff17 100644 --- a/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/BlobProperties.java +++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/BlobProperties.java @@ -31,6 +31,9 @@ public interface BlobProperties extends Comparable { */ BlobType getType(); + /** @return access tier or null if not set */ + AccessTier getTier(); + LeaseStatus getLeaseStatus(); URI getUrl(); diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/MutableBlobProperties.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/MutableBlobProperties.java index ce7287547e..f881117ad6 100644 --- a/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/MutableBlobProperties.java +++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/MutableBlobProperties.java @@ -40,6 +40,8 @@ public interface MutableBlobProperties extends BlobProperties { * @see ListableContainerProperties#getContainer */ void setContainer(String container); + + void setTier(AccessTier tier); /** * @see ListableContainerProperties#getLastModified diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/internal/BlobPropertiesImpl.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/internal/BlobPropertiesImpl.java index c3c400541d..6e8c63521e 100644 --- a/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/internal/BlobPropertiesImpl.java +++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/internal/BlobPropertiesImpl.java @@ -23,6 +23,7 @@ import java.util.Date; import java.util.Map; import org.jclouds.azureblob.domain.BlobProperties; +import org.jclouds.azureblob.domain.AccessTier; import org.jclouds.azureblob.domain.BlobType; import org.jclouds.azureblob.domain.LeaseStatus; import org.jclouds.io.ContentMetadata; @@ -37,6 +38,7 @@ import com.google.common.collect.Maps; public class BlobPropertiesImpl implements BlobProperties { private final BlobType type; + private final AccessTier tier; private final String name; private final String container; private final URI url; @@ -46,12 +48,21 @@ public class BlobPropertiesImpl implements BlobProperties { private final LeaseStatus leaseStatus; private final BaseImmutableContentMetadata contentMetadata; - // TODO: should this take Cache-Control as well? + @Deprecated public BlobPropertiesImpl(BlobType type, String name, String container, URI url, @Nullable Date lastModified, @Nullable String eTag, long size, String contentType, @Nullable byte[] contentMD5, @Nullable String contentMetadata, @Nullable String contentLanguage, @Nullable Date currentExpires, LeaseStatus leaseStatus, Map metadata) { + this(type, null, name, container, url, lastModified, eTag, size, contentType, contentMD5, contentMetadata, contentLanguage, currentExpires, leaseStatus, metadata); + } + + // TODO: should this take Cache-Control as well? + public BlobPropertiesImpl(BlobType type, @Nullable AccessTier tier, String name, String container, URI url, @Nullable Date lastModified, @Nullable String eTag, + long size, String contentType, @Nullable byte[] contentMD5, @Nullable String contentMetadata, + @Nullable String contentLanguage, @Nullable Date currentExpires, LeaseStatus leaseStatus, + Map metadata) { this.type = checkNotNull(type, "type"); + this.tier = tier; this.leaseStatus = checkNotNull(leaseStatus, "leaseStatus"); this.name = checkNotNull(name, "name"); this.container = checkNotNull(container, "container"); @@ -71,6 +82,11 @@ public class BlobPropertiesImpl implements BlobProperties { return type; } + @Override + public AccessTier getTier() { + return tier; + } + /** *{@inheritDoc} */ diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/internal/MutableBlobPropertiesImpl.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/internal/MutableBlobPropertiesImpl.java index 67fd62a55d..517fe8a020 100644 --- a/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/internal/MutableBlobPropertiesImpl.java +++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/domain/internal/MutableBlobPropertiesImpl.java @@ -16,10 +16,13 @@ */ package org.jclouds.azureblob.domain.internal; +import static com.google.common.base.Preconditions.checkNotNull; + import java.net.URI; import java.util.Date; import java.util.Map; +import org.jclouds.azureblob.domain.AccessTier; import org.jclouds.azureblob.domain.BlobProperties; import org.jclouds.azureblob.domain.BlobType; import org.jclouds.azureblob.domain.LeaseStatus; @@ -36,6 +39,7 @@ import com.google.common.collect.Maps; public class MutableBlobPropertiesImpl implements MutableBlobProperties { private BlobType type = BlobType.BLOCK_BLOB; + private AccessTier tier; private LeaseStatus leaseStatus = LeaseStatus.UNLOCKED; private String name; @@ -77,6 +81,16 @@ public class MutableBlobPropertiesImpl implements MutableBlobProperties { this.type = type; } + @Override + public AccessTier getTier() { + return tier; + } + + @Override + public void setTier(AccessTier tier) { + this.tier = checkNotNull(tier); + } + /** *{@inheritDoc} */ diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/functions/ParseBlobPropertiesFromHeaders.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/functions/ParseBlobPropertiesFromHeaders.java index f480426d23..c7446344a9 100644 --- a/providers/azureblob/src/main/java/org/jclouds/azureblob/functions/ParseBlobPropertiesFromHeaders.java +++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/functions/ParseBlobPropertiesFromHeaders.java @@ -21,6 +21,7 @@ import static com.google.common.base.Preconditions.checkArgument; import javax.inject.Inject; import org.jclouds.azureblob.blobstore.functions.BlobMetadataToBlobProperties; +import org.jclouds.azureblob.domain.AccessTier; import org.jclouds.azureblob.domain.MutableBlobProperties; import org.jclouds.blobstore.domain.BlobMetadata; import org.jclouds.blobstore.functions.ParseSystemAndUserMetadataFromHeaders; @@ -55,6 +56,10 @@ public class ParseBlobPropertiesFromHeaders implements Function method = method(AzureBlobClient.class, "setBlobTier", String.class, String.class, AccessTier.class); + GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("container", "blob", tier)); + + assertRequestLineEquals(request, + "PUT https://identity.blob.core.windows.net/container/blob?comp=tier HTTP/1.1"); + assertNonPayloadHeadersEqual(request, + "x-ms-access-tier: " + tier + "\n" + + "x-ms-version: 2017-04-17\n"); + assertPayloadEquals(request, null, null, false); + + assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, null); + } + public void testCopyBlob() throws Exception { Invokable method = method(AzureBlobClient.class, "copyBlob", URI.class, String.class, String.class, CopyBlobOptions.class); GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of( diff --git a/providers/azureblob/src/test/java/org/jclouds/azureblob/xml/ContainerNameEnumerationResultsHandlerTest.java b/providers/azureblob/src/test/java/org/jclouds/azureblob/xml/ContainerNameEnumerationResultsHandlerTest.java index 16f11c1c9d..a2927489c6 100644 --- a/providers/azureblob/src/test/java/org/jclouds/azureblob/xml/ContainerNameEnumerationResultsHandlerTest.java +++ b/providers/azureblob/src/test/java/org/jclouds/azureblob/xml/ContainerNameEnumerationResultsHandlerTest.java @@ -22,6 +22,7 @@ import java.io.InputStream; import java.net.URI; import java.util.Set; +import org.jclouds.azureblob.domain.AccessTier; import org.jclouds.azureblob.domain.BlobProperties; import org.jclouds.azureblob.domain.BlobType; import org.jclouds.azureblob.domain.LeaseStatus; @@ -56,17 +57,17 @@ public class ContainerNameEnumerationResultsHandlerTest extends BaseHandlerTest public void testApplyInputStream() { InputStream is = getClass().getResourceAsStream("/test_list_blobs.xml"); Set contents = ImmutableSet. of( - new BlobPropertiesImpl(BlobType.BLOCK_BLOB, "blob1.txt", "mycontainer", URI + new BlobPropertiesImpl(BlobType.BLOCK_BLOB, AccessTier.HOT, "blob1.txt", "mycontainer", URI .create("http://myaccount.blob.core.windows.net/mycontainer/blob1.txt"), dateService .rfc822DateParse("Thu, 18 Sep 2008 18:41:57 GMT"), "0x8CAE7D55D050B8B", 8, "text/plain; charset=UTF-8", null, null, null, null, LeaseStatus.UNLOCKED, ImmutableMap . of()), - new BlobPropertiesImpl(BlobType.BLOCK_BLOB, "blob2.txt", "mycontainer", URI + new BlobPropertiesImpl(BlobType.BLOCK_BLOB, AccessTier.COOL, "blob2.txt", "mycontainer", URI .create("http://myaccount.blob.core.windows.net/mycontainer/blob2.txt"), dateService .rfc822DateParse("Thu, 18 Sep 2008 18:41:57 GMT"), "0x8CAE7D55CF6C339", 14, "text/plain; charset=UTF-8", null, null, null, null, LeaseStatus.UNLOCKED, ImmutableMap . of()), - new BlobPropertiesImpl(BlobType.PAGE_BLOB, "newblob1.txt", "mycontainer", URI + new BlobPropertiesImpl(BlobType.PAGE_BLOB, AccessTier.ARCHIVE, "newblob1.txt", "mycontainer", URI .create("http://myaccount.blob.core.windows.net/mycontainer/newblob1.txt"), dateService .rfc822DateParse("Thu, 18 Sep 2008 18:41:57 GMT"), "0x8CAE7D55CF6C339", 25, "text/plain; charset=UTF-8", null, null, null, null, LeaseStatus.UNLOCKED, ImmutableMap @@ -84,7 +85,7 @@ public class ContainerNameEnumerationResultsHandlerTest extends BaseHandlerTest public void testOptions() { InputStream is = getClass().getResourceAsStream("/test_list_blobs_options.xml"); - Set contents = ImmutableSet. of(new BlobPropertiesImpl(BlobType.BLOCK_BLOB, "a", + Set contents = ImmutableSet. of(new BlobPropertiesImpl(BlobType.BLOCK_BLOB, AccessTier.HOT, "a", "adriancole-blobstore3", URI.create("https://jclouds.blob.core.windows.net/adriancole-blobstore3/a"), dateService.rfc822DateParse("Sat, 30 Jan 2010 17:46:15 GMT"), "0x8CC6FEB41736428", 8, "application/octet-stream", null, null, null, null, LeaseStatus.UNLOCKED, ImmutableMap. of())); diff --git a/providers/azureblob/src/test/resources/test_list_blobs.xml b/providers/azureblob/src/test/resources/test_list_blobs.xml index ab040a3598..f7a5229881 100644 --- a/providers/azureblob/src/test/resources/test_list_blobs.xml +++ b/providers/azureblob/src/test/resources/test_list_blobs.xml @@ -13,6 +13,7 @@ 8 text/plain; charset=UTF-8 BlockBlob + Hot unlocked @@ -26,6 +27,7 @@ 14 text/plain; charset=UTF-8 BlockBlob + Cool unlocked @@ -42,6 +44,7 @@ 25 text/plain; charset=UTF-8 PageBlob + Archive unlocked diff --git a/providers/azureblob/src/test/resources/test_list_blobs_options.xml b/providers/azureblob/src/test/resources/test_list_blobs_options.xml index 55a33f41b0..de52605852 100644 --- a/providers/azureblob/src/test/resources/test_list_blobs_options.xml +++ b/providers/azureblob/src/test/resources/test_list_blobs_options.xml @@ -18,6 +18,7 @@ BlockBlob + Hot unlocked