mirror of https://github.com/apache/jclouds.git
JCLOUDS-1335: Azure Blob object access tiers
This commit is contained in:
parent
5facb65a7e
commit
fc147dc0c5
|
@ -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<String, String> 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.
|
||||
|
|
|
@ -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")));
|
||||
}
|
||||
}
|
|
@ -31,6 +31,9 @@ public interface BlobProperties extends Comparable<BlobProperties> {
|
|||
*/
|
||||
BlobType getType();
|
||||
|
||||
/** @return access tier or null if not set */
|
||||
AccessTier getTier();
|
||||
|
||||
LeaseStatus getLeaseStatus();
|
||||
|
||||
URI getUrl();
|
||||
|
|
|
@ -40,6 +40,8 @@ public interface MutableBlobProperties extends BlobProperties {
|
|||
* @see ListableContainerProperties#getContainer
|
||||
*/
|
||||
void setContainer(String container);
|
||||
|
||||
void setTier(AccessTier tier);
|
||||
|
||||
/**
|
||||
* @see ListableContainerProperties#getLastModified
|
||||
|
|
|
@ -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<String, String> 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<String, String> 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}
|
||||
*/
|
||||
|
|
|
@ -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}
|
||||
*/
|
||||
|
|
|
@ -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<HttpResponse, Mu
|
|||
BlobMetadata base = blobMetadataParser.apply(from);
|
||||
MutableBlobProperties to = blobToBlobProperties.apply(base);
|
||||
to.setContainer(container);
|
||||
String tier = from.getFirstHeaderOrNull("x-ms-access-tier");
|
||||
if (tier != null) {
|
||||
to.setTier(AccessTier.fromValue(tier));
|
||||
}
|
||||
return to;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.util.Set;
|
|||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.jclouds.azureblob.domain.AccessTier;
|
||||
import org.jclouds.azureblob.domain.BlobProperties;
|
||||
import org.jclouds.azureblob.domain.BlobType;
|
||||
import org.jclouds.azureblob.domain.LeaseStatus;
|
||||
|
@ -70,6 +71,7 @@ public class ContainerNameEnumerationResultsHandler extends ParseSax.HandlerWith
|
|||
private String currentContentEncoding;
|
||||
private String currentContentLanguage;
|
||||
private BlobType currentBlobType;
|
||||
private AccessTier currentAccessTier;
|
||||
private Date currentExpires;
|
||||
private boolean inBlob;
|
||||
private boolean inBlobPrefix;
|
||||
|
@ -129,16 +131,19 @@ public class ContainerNameEnumerationResultsHandler extends ParseSax.HandlerWith
|
|||
nextMarker = (nextMarker.equals("")) ? null : nextMarker;
|
||||
} else if (qName.equals("BlobType")) {
|
||||
currentBlobType = BlobType.fromValue(currentText.toString());
|
||||
} else if (qName.equals("AccessTier")) {
|
||||
currentAccessTier = AccessTier.fromValue(currentText.toString());
|
||||
} else if (qName.equals("LeaseStatus")) {
|
||||
currentLeaseStatus = LeaseStatus.fromValue(currentText.toString());
|
||||
} else if (qName.equals("Blob")) {
|
||||
URI currentUrl = uriBuilder(containerUrl).appendPath(Strings2.urlEncode(currentName)).build();
|
||||
BlobProperties md = new BlobPropertiesImpl(currentBlobType, currentName, containerUrl.getPath().replace("/",
|
||||
BlobProperties md = new BlobPropertiesImpl(currentBlobType, currentAccessTier, currentName, containerUrl.getPath().replace("/",
|
||||
""), currentUrl, currentLastModified, currentETag, currentSize, currentContentType,
|
||||
currentContentMD5, currentContentEncoding, currentContentLanguage, currentExpires,
|
||||
currentLeaseStatus, currentMetadata);
|
||||
blobMetadata.add(md);
|
||||
currentBlobType = null;
|
||||
currentAccessTier = null;
|
||||
currentName = null;
|
||||
currentLastModified = null;
|
||||
currentETag = null;
|
||||
|
|
|
@ -38,6 +38,7 @@ import java.util.Set;
|
|||
import org.jclouds.azure.storage.AzureStorageResponseException;
|
||||
import org.jclouds.azure.storage.domain.BoundedSet;
|
||||
import org.jclouds.azure.storage.options.ListOptions;
|
||||
import org.jclouds.azureblob.domain.AccessTier;
|
||||
import org.jclouds.azureblob.domain.AzureBlob;
|
||||
import org.jclouds.azureblob.domain.BlobProperties;
|
||||
import org.jclouds.azureblob.domain.ContainerProperties;
|
||||
|
@ -560,7 +561,7 @@ public class AzureBlobClientLiveTest extends BaseBlobStoreIntegrationTest {
|
|||
assertEquals(ByteStreams2.toByteArrayAndClose(getBlob.getPayload().openStream()), byteSource.read());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test(timeOut = 5 * 60 * 1000, dependsOnMethods = { "testCreateContainer" })
|
||||
public void testSetBlobProperties() throws Exception {
|
||||
String blobName = "blob-name";
|
||||
ByteSource byteSource = TestUtils.randomByteSource().slice(0, 1024);
|
||||
|
@ -591,4 +592,35 @@ public class AzureBlobClientLiveTest extends BaseBlobStoreIntegrationTest {
|
|||
assertThat(contentMetadata.getContentLanguage()).isEqualTo(contentLanguage);
|
||||
assertThat(contentMetadata.getContentType()).isEqualTo(contentType);
|
||||
}
|
||||
|
||||
@Test(timeOut = 5 * 60 * 1000, dependsOnMethods = { "testCreateContainer" })
|
||||
public void testSetBlobTier() throws Exception {
|
||||
String blobName = "tier-blob-name";
|
||||
ByteSource byteSource = TestUtils.randomByteSource().slice(0, 1024);
|
||||
|
||||
// create blob
|
||||
AzureBlob object = getApi().newBlob();
|
||||
object.getProperties().setName(blobName);
|
||||
object.setPayload(byteSource.read());
|
||||
getApi().putBlob(privateContainer, object);
|
||||
|
||||
// default
|
||||
BlobProperties properties = getApi().getBlobProperties(privateContainer, blobName);
|
||||
assertThat(properties.getTier()).isNull();
|
||||
|
||||
// hot
|
||||
getApi().setBlobTier(privateContainer, blobName, AccessTier.HOT);
|
||||
properties = getApi().getBlobProperties(privateContainer, blobName);
|
||||
assertThat(properties.getTier()).isEqualTo(AccessTier.HOT);
|
||||
|
||||
// cool
|
||||
getApi().setBlobTier(privateContainer, blobName, AccessTier.COOL);
|
||||
properties = getApi().getBlobProperties(privateContainer, blobName);
|
||||
assertThat(properties.getTier()).isEqualTo(AccessTier.COOL);
|
||||
|
||||
// archive
|
||||
getApi().setBlobTier(privateContainer, blobName, AccessTier.ARCHIVE);
|
||||
properties = getApi().getBlobProperties(privateContainer, blobName);
|
||||
assertThat(properties.getTier()).isEqualTo(AccessTier.ARCHIVE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.jclouds.Fallbacks.VoidOnNotFoundOr404;
|
|||
import org.jclouds.azure.storage.filters.SharedKeyLiteAuthentication;
|
||||
import org.jclouds.azure.storage.options.ListOptions;
|
||||
import org.jclouds.azureblob.AzureBlobFallbacks.FalseIfContainerAlreadyExists;
|
||||
import org.jclouds.azureblob.domain.AccessTier;
|
||||
import org.jclouds.azureblob.domain.AzureBlob;
|
||||
import org.jclouds.azureblob.domain.ListBlobsInclude;
|
||||
import org.jclouds.azureblob.domain.PublicAccess;
|
||||
|
@ -379,6 +380,23 @@ public class AzureBlobClientTest extends BaseRestAnnotationProcessingTest<AzureB
|
|||
assertFallbackClassEquals(method, null);
|
||||
}
|
||||
|
||||
public void testSetBlobTier() throws Exception {
|
||||
AccessTier tier = AccessTier.COOL;
|
||||
Invokable<?, ?> method = method(AzureBlobClient.class, "setBlobTier", String.class, String.class, AccessTier.class);
|
||||
GeneratedHttpRequest request = processor.createRequest(method, ImmutableList.<Object> 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.<Object> of(
|
||||
|
|
|
@ -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<BlobProperties> contents = ImmutableSet.<BlobProperties> 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
|
||||
.<String, String> 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
|
||||
.<String, String> 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<BlobProperties> contents = ImmutableSet.<BlobProperties> of(new BlobPropertiesImpl(BlobType.BLOCK_BLOB, "a",
|
||||
Set<BlobProperties> contents = ImmutableSet.<BlobProperties> 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.<String, String> of()));
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
<Content-Length>8</Content-Length>
|
||||
<Content-Type>text/plain; charset=UTF-8</Content-Type>
|
||||
<BlobType>BlockBlob</BlobType>
|
||||
<AccessTier>Hot</AccessTier>
|
||||
<LeaseStatus>unlocked</LeaseStatus>
|
||||
<Content-Encoding />
|
||||
<Content-Language />
|
||||
|
@ -26,6 +27,7 @@
|
|||
<Content-Length>14</Content-Length>
|
||||
<Content-Type>text/plain; charset=UTF-8</Content-Type>
|
||||
<BlobType>BlockBlob</BlobType>
|
||||
<AccessTier>Cool</AccessTier>
|
||||
<LeaseStatus>unlocked</LeaseStatus>
|
||||
<Content-Encoding />
|
||||
<Content-Language />
|
||||
|
@ -42,6 +44,7 @@
|
|||
<Content-Length>25</Content-Length>
|
||||
<Content-Type>text/plain; charset=UTF-8</Content-Type>
|
||||
<BlobType>PageBlob</BlobType>
|
||||
<AccessTier>Archive</AccessTier>
|
||||
<LeaseStatus>unlocked</LeaseStatus>
|
||||
<Content-Encoding />
|
||||
<Content-Language />
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
<Content-MD5 />
|
||||
<Cache-Control />
|
||||
<BlobType>BlockBlob</BlobType>
|
||||
<AccessTier>Hot</AccessTier>
|
||||
<LeaseStatus>unlocked</LeaseStatus>
|
||||
</Properties>
|
||||
<Metadata />
|
||||
|
|
Loading…
Reference in New Issue