Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat: integrate disabling Lifecycle rule api for to removing lifecycl…
…erules from bucket
  • Loading branch information
athakor committed May 18, 2020
commit a73af3e68eab8624e0d6dd97eac9a68fd9010fc5
8 changes: 8 additions & 0 deletions google-cloud-storage/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@
<groupId>io.opencensus</groupId>
<artifactId>opencensus-api</artifactId>
</dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-iamcredentials</artifactId>
</dependency>
<dependency>
<groupId>com.google.api.grpc</groupId>
<artifactId>proto-google-iam-v1</artifactId>
Expand Down Expand Up @@ -190,6 +194,10 @@
<artifactId>httpcore</artifactId>
<scope>test</scope>
</dependency>
Comment thread
athakor marked this conversation as resolved.
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1114,6 +1114,16 @@ public boolean deleteDefaultAcl(Entity entity) {
return storage.deleteDefaultAcl(getName(), entity);
}

/**
* Disable or delete lifecycle rules of the requested bucket.
*
* @return {@code true} if the bucket lifecycle rules was deleted.
* @throws StorageException upon failure
*/
public boolean disableLifeCycleRule(Bucket bucket, String serviceAccount) {
return storage.disableLifeCycleRule(bucket, serviceAccount);
}

/**
* Creates a new default blob ACL entry on this bucket.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3076,6 +3076,14 @@ PostPolicyV4 generateSignedPostPolicyV4(
*/
boolean deleteDefaultAcl(String bucket, Entity entity);

/**
* Disable or delete lifecycle rules of the requested bucket.
*
* @return {@code true} if the bucket lifecycle rules was deleted.
* @throws StorageException upon failure
*/
boolean disableLifeCycleRule(BucketInfo bucketInfo, String serviceAccount);

/**
* Creates a new default blob ACL entry on the specified bucket.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1158,6 +1158,25 @@ public Boolean call() {
}
}

@Override
public boolean disableLifeCycleRule(final BucketInfo bucketInfo, final String serviceAccount) {
final com.google.api.services.storage.model.Bucket bucketPb = bucketInfo.toPb();
try {
return runWithRetries(
new Callable<Boolean>() {
@Override
public Boolean call() {
return storageRpc.disableLifeCycleRule(bucketPb, serviceAccount);
}
},
getOptions().getRetrySettings(),
EXCEPTION_HANDLER,
getOptions().getClock());
} catch (RetryHelperException e) {
throw StorageException.translateAndThrow(e);
}
}

@Override
public boolean deleteAcl(final String bucket, final Entity entity) {
return deleteAcl(bucket, entity, new BucketSourceOption[0]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.google.api.client.googleapis.json.GoogleJsonError;
import com.google.api.client.http.ByteArrayContent;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpContent;
import com.google.api.client.http.HttpHeaders;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestFactory;
Expand All @@ -33,6 +34,7 @@
import com.google.api.client.http.HttpResponseException;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.InputStreamContent;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.http.json.JsonHttpContent;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
Expand All @@ -57,6 +59,9 @@
import com.google.cloud.Tuple;
import com.google.cloud.http.CensusHttpModule;
import com.google.cloud.http.HttpTransportOptions;
import com.google.cloud.iam.credentials.v1.GenerateAccessTokenRequest;
import com.google.cloud.iam.credentials.v1.GenerateAccessTokenResponse;
import com.google.cloud.iam.credentials.v1.IamCredentialsClient;
import com.google.cloud.storage.StorageException;
import com.google.cloud.storage.StorageOptions;
import com.google.common.base.Function;
Expand All @@ -66,6 +71,7 @@
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;
import com.google.common.io.BaseEncoding;
import com.google.protobuf.Duration;
import io.opencensus.common.Scope;
import io.opencensus.trace.AttributeValue;
import io.opencensus.trace.Span;
Expand All @@ -87,7 +93,11 @@ public class HttpStorageRpc implements StorageRpc {
public static final String NO_ACL_PROJECTION = "noAcl";
private static final String ENCRYPTION_KEY_PREFIX = "x-goog-encryption-";
private static final String SOURCE_ENCRYPTION_KEY_PREFIX = "x-goog-copy-source-encryption-";

private static final String GOOGLE_STORAGE_API_ENDPOINT =
"https://storage.googleapis.com/storage/v1/b/";
private static final String GOOGLE_API_CLOUD_SCOPE =
"https://www.googleapis.com/auth/cloud-platform";
private static final Duration LIFE_TIME = Duration.newBuilder().setSeconds(3600).build();
// declare this HttpStatus code here as it's not included in java.net.HttpURLConnection
private static final int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;

Expand Down Expand Up @@ -1000,6 +1010,47 @@ public boolean deleteAcl(String bucket, String entity, Map<Option, ?> options) {
}
}

@Override
public boolean disableLifeCycleRule(Bucket bucket, String serviceAccount) {
Span span = startSpan(HttpStorageRpcSpans.SPAN_NAME_DELETE_BUCKET_LIFECYCLE_RULE);
Scope scope = tracer.withSpan(span);
try {
IamCredentialsClient client = IamCredentialsClient.create();
GenerateAccessTokenRequest request =
GenerateAccessTokenRequest.newBuilder()
.setName(serviceAccount)
.addScope(GOOGLE_API_CLOUD_SCOPE)
.setLifetime(LIFE_TIME)
.build();
GenerateAccessTokenResponse accessTokenResponse = client.generateAccessToken(request);
HttpHeaders headers = new HttpHeaders();
headers.setAuthorization("Bearer " + accessTokenResponse.getAccessToken());
headers.setContentType("application/json");

HttpRequestFactory requestFactory = new NetHttpTransport().createRequestFactory();
HttpContent httpContent = new JsonHttpContent(new JacksonFactory(), "");
HttpRequest httpRequest =
requestFactory
.buildPutRequest(
new GenericUrl(
GOOGLE_STORAGE_API_ENDPOINT + bucket.getName() + "?fields=lifecycle"),
httpContent)
.setHeaders(headers);
httpRequest.execute();
return true;
} catch (IOException ex) {
span.setStatus(Status.UNKNOWN.withDescription(ex.getMessage()));
StorageException serviceException = translate(ex);
if (serviceException.getCode() == HTTP_NOT_FOUND) {
return false;
}
throw serviceException;
} finally {
scope.close();
span.end();
}
}

@Override
public BucketAccessControl createAcl(BucketAccessControl acl, Map<Option, ?> options) {
Span span = startSpan(HttpStorageRpcSpans.SPAN_NAME_CREATE_BUCKET_ACL);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ class HttpStorageRpcSpans {
static final String SPAN_NAME_PATCH_BUCKET = getTraceSpanName("patch(Bucket,Map)");
static final String SPAN_NAME_PATCH_OBJECT = getTraceSpanName("patch(StorageObject,Map)");
static final String SPAN_NAME_DELETE_BUCKET = getTraceSpanName("delete(Bucket,Map)");
static final String SPAN_NAME_DELETE_BUCKET_LIFECYCLE_RULE =
getTraceSpanName("delete(Bucket,String)");
static final String SPAN_NAME_DELETE_OBJECT = getTraceSpanName("delete(StorageObject,Map)");
static final String SPAN_NAME_CREATE_BATCH = getTraceSpanName("createBatch()");
static final String SPAN_NAME_COMPOSE = getTraceSpanName("compose(Iterable,StorageObject,Map)");
Expand Down Expand Up @@ -96,7 +98,6 @@ class HttpStorageRpcSpans {
getTraceSpanName(RpcBatch.class.getName() + ".submit()");
static final EndSpanOptions END_SPAN_OPTIONS =
EndSpanOptions.builder().setSampleToLocalSpanStore(true).build();

static String getTraceSpanName(String methodDescriptor) {
return String.format(
"%s.%s.%s", SPAN_NAME_CLIENT_PREFIX, HttpStorageRpc.class.getName(), methodDescriptor);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,14 @@ public int hashCode() {
*/
boolean delete(Bucket bucket, Map<Option, ?> options);

/**
* Disable or delete lifecycle rules of the requested bucket.
*
* @return {@code true} if the bucket lifecycle rule was disable.
* @throws StorageException upon failure
*/
boolean disableLifeCycleRule(Bucket bucket, String serviceAccount);

/**
* Deletes the requested storage object.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@
import com.google.common.collect.Lists;
import com.google.common.io.BaseEncoding;
import com.google.common.io.ByteStreams;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.iam.v1.Binding;
import com.google.iam.v1.IAMPolicyGrpc;
import com.google.iam.v1.SetIamPolicyRequest;
Expand Down Expand Up @@ -181,6 +183,10 @@ public class ITStorageTest {
&& System.getenv("GOOGLE_CLOUD_TESTS_IN_VPCSC").equalsIgnoreCase("true");
private static final List<String> LOCATION_TYPES =
ImmutableList.of("multi-region", "region", "dual-region");
private static final String GOOGLE_API_CLIENT_EMAIL = "clientEmail";
private static final String GOOGLE_API_CLOUD_SCOPE =
"https://www.googleapis.com/auth/cloud-platform";
private static final String REGEXP = "^\"|\"$";

@BeforeClass
public static void beforeClass() throws IOException {
Expand Down Expand Up @@ -3250,7 +3256,7 @@ public void testBlobReload() throws Exception {
String blobName = "test-blob-reload";
BlobId blobId = BlobId.of(BUCKET, blobName);
BlobInfo blobInfo = BlobInfo.newBuilder(blobId).build();
Blob blob = storage.create(blobInfo, new byte[] {0, 1, 2});
Blob blob = storage.create(blobInfo, new byte[]{0, 1, 2});

Blob blobUnchanged = blob.reload();
assertEquals(blob, blobUnchanged);
Expand All @@ -3273,4 +3279,44 @@ public void testBlobReload() throws Exception {
updated.delete();
assertNull(updated.reload());
}

@Test
public void testDisableLifeCycleRule() throws Exception {
String lifeCycleRuleBucket = RemoteStorageHelper.generateBucketName();
List<LifecycleRule> lifecycleRules =
ImmutableList.of(
new LifecycleRule(
LifecycleAction.newDeleteAction(),
LifecycleCondition.newBuilder().setAge(2).build()));
try {
Bucket bucket =
storage.create(
BucketInfo.newBuilder(lifeCycleRuleBucket)
.setStorageClass(StorageClass.COLDLINE)
.setLocation("us-central1")
.setLifecycleRules(lifecycleRules)
.build());
assertEquals(lifeCycleRuleBucket, bucket.getName());
assertEquals(StorageClass.COLDLINE, bucket.getStorageClass());
assertEquals(lifecycleRules, bucket.getLifecycleRules());
boolean isDisable =
bucket.disableLifeCycleRule(bucket, getFromCredential(GOOGLE_API_CLIENT_EMAIL));
if (isDisable) {
bucket =
storage.get(
lifeCycleRuleBucket, Storage.BucketGetOption.fields(Storage.BucketField.values()));
assertNull(bucket.getLifecycleRules());
}
} finally {
RemoteStorageHelper.forceDelete(storage, lifeCycleRuleBucket, 5, TimeUnit.SECONDS);
}
}

private static String getFromCredential(String key) throws Exception {
Gson gson = new Gson();
GoogleCredentials credentials =
GoogleCredentials.getApplicationDefault().createScoped(GOOGLE_API_CLOUD_SCOPE);
JsonObject jsonObject = gson.fromJson(gson.toJson(credentials), JsonObject.class);
return jsonObject.get(key).toString().replaceAll(REGEXP, "");
}
}
11 changes: 11 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
<site.installationModule>google-cloud-storage-parent</site.installationModule>
<google.core.version>1.93.4</google.core.version>
<google.api-common.version>1.9.0</google.api-common.version>
<protobuf.version>3.11.1</protobuf.version>
Comment thread
athakor marked this conversation as resolved.
Outdated
<junit.version>4.13</junit.version>
<threeten.version>1.4.4</threeten.version>
<javax.annotations.version>1.3.2</javax.annotations.version>
Expand Down Expand Up @@ -146,6 +147,16 @@
<artifactId>api-common</artifactId>
<version>${google.api-common.version}</version>
</dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-iamcredentials</artifactId>
<version>0.43.0-alpha</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>${protobuf.version}</version>
</dependency>
<dependency>
<groupId>com.google.api.grpc</groupId>
<artifactId>proto-google-iam-v1</artifactId>
Expand Down