From 1e0e63ddd24852b1fc121885354f6851ff43bbae Mon Sep 17 00:00:00 2001 From: "adrian.f.cole" Date: Wed, 30 Dec 2009 21:58:15 +0000 Subject: [PATCH] Issue 23: added bucket logging git-svn-id: http://jclouds.googlecode.com/svn/trunk@2548 3d8758e0-26b5-11de-8745-db77d3ebf521 --- .../org/jclouds/aws/s3/S3AsyncClient.java | 32 ++++ .../java/org/jclouds/aws/s3/S3Client.java | 37 +++++ .../aws/s3/binders/BindACLToXMLPayload.java | 4 + .../BindBucketLoggingToXmlPayload.java | 97 ++++++++++++ .../BindNoBucketLoggingToXmlPayload.java | 45 ++++++ .../aws/s3/domain/AccessControlList.java | 56 +++++++ .../jclouds/aws/s3/domain/BucketLogging.java | 149 ++++++++++++++++++ .../aws/s3/xml/BucketLoggingHandler.java | 102 ++++++++++++ .../org/jclouds/aws/s3/S3AsyncClientTest.java | 61 +++++++ .../BindBucketLoggingToXmlPayloadTest.java | 48 ++++++ .../BindNoBucketLoggingToXmlPayloadTest.java | 35 ++++ .../aws/s3/internal/StubS3AsyncClient.java | 28 ++++ .../aws/s3/services/BucketsLiveTest.java | 64 +++++++- .../aws/s3/xml/BucketLoggingHandlerTest.java | 61 +++++++ .../src/test/resources/s3/bucket_logging.xml | 1 + 15 files changed, 819 insertions(+), 1 deletion(-) create mode 100644 aws/core/src/main/java/org/jclouds/aws/s3/binders/BindBucketLoggingToXmlPayload.java create mode 100644 aws/core/src/main/java/org/jclouds/aws/s3/binders/BindNoBucketLoggingToXmlPayload.java create mode 100644 aws/core/src/main/java/org/jclouds/aws/s3/domain/BucketLogging.java create mode 100644 aws/core/src/main/java/org/jclouds/aws/s3/xml/BucketLoggingHandler.java create mode 100644 aws/core/src/test/java/org/jclouds/aws/s3/binders/BindBucketLoggingToXmlPayloadTest.java create mode 100644 aws/core/src/test/java/org/jclouds/aws/s3/binders/BindNoBucketLoggingToXmlPayloadTest.java create mode 100644 aws/core/src/test/java/org/jclouds/aws/s3/xml/BucketLoggingHandlerTest.java create mode 100644 aws/core/src/test/resources/s3/bucket_logging.xml diff --git a/aws/core/src/main/java/org/jclouds/aws/s3/S3AsyncClient.java b/aws/core/src/main/java/org/jclouds/aws/s3/S3AsyncClient.java index e9a2bd40ed..1a4db23087 100644 --- a/aws/core/src/main/java/org/jclouds/aws/s3/S3AsyncClient.java +++ b/aws/core/src/main/java/org/jclouds/aws/s3/S3AsyncClient.java @@ -37,9 +37,12 @@ import javax.ws.rs.Path; import javax.ws.rs.PathParam; import org.jclouds.aws.s3.binders.BindACLToXMLPayload; +import org.jclouds.aws.s3.binders.BindBucketLoggingToXmlPayload; +import org.jclouds.aws.s3.binders.BindNoBucketLoggingToXmlPayload; import org.jclouds.aws.s3.binders.BindPayerToXmlPayload; import org.jclouds.aws.s3.binders.BindS3ObjectToPayload; import org.jclouds.aws.s3.domain.AccessControlList; +import org.jclouds.aws.s3.domain.BucketLogging; import org.jclouds.aws.s3.domain.BucketMetadata; import org.jclouds.aws.s3.domain.ListBucketResponse; import org.jclouds.aws.s3.domain.ObjectMetadata; @@ -57,6 +60,7 @@ import org.jclouds.aws.s3.options.ListBucketOptions; import org.jclouds.aws.s3.options.PutBucketOptions; import org.jclouds.aws.s3.options.PutObjectOptions; import org.jclouds.aws.s3.xml.AccessControlListHandler; +import org.jclouds.aws.s3.xml.BucketLoggingHandler; import org.jclouds.aws.s3.xml.CopyObjectHandler; import org.jclouds.aws.s3.xml.ListAllMyBucketsHandler; import org.jclouds.aws.s3.xml.ListBucketHandler; @@ -268,4 +272,32 @@ public interface S3AsyncClient { Future putObjectACL(@HostPrefixParam String bucketName, @PathParam("key") String key, @BinderParam(BindACLToXMLPayload.class) AccessControlList acl); + /** + * @see S3Client#getBucketLogging + */ + @GET + @QueryParams(keys = "logging") + @XMLResponseParser(BucketLoggingHandler.class) + @ExceptionParser(ThrowContainerNotFoundOn404.class) + @Path("/") + Future getBucketLogging(@HostPrefixParam String bucketName); + + /** + * @see S3Client#enableBucketLogging + */ + @PUT + @Path("/") + @QueryParams(keys = "logging") + Future enableBucketLogging(@HostPrefixParam String bucketName, + @BinderParam(BindBucketLoggingToXmlPayload.class) BucketLogging logging); + + /** + * @see S3Client#putBucketLogging + */ + @PUT + @Path("/") + @QueryParams(keys = "logging") + Future disableBucketLogging( + @BinderParam(BindNoBucketLoggingToXmlPayload.class) @HostPrefixParam String bucketName); + } diff --git a/aws/core/src/main/java/org/jclouds/aws/s3/S3Client.java b/aws/core/src/main/java/org/jclouds/aws/s3/S3Client.java index 252fa3faff..789f6ac251 100644 --- a/aws/core/src/main/java/org/jclouds/aws/s3/S3Client.java +++ b/aws/core/src/main/java/org/jclouds/aws/s3/S3Client.java @@ -29,6 +29,7 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import org.jclouds.aws.s3.domain.AccessControlList; +import org.jclouds.aws.s3.domain.BucketLogging; import org.jclouds.aws.s3.domain.BucketMetadata; import org.jclouds.aws.s3.domain.ListBucketResponse; import org.jclouds.aws.s3.domain.ObjectMetadata; @@ -388,4 +389,40 @@ public interface S3Client { * /> */ void setBucketPayer(String bucketName, Payer payer); + + /** + * Inspects the logging status for a bucket. + * + * + * @param bucketName + * the bucket you wish to know the logging status + * @return bucketLogging configuration or null, if not configured + * + * @see + */ + BucketLogging getBucketLogging(String bucketName); + + /** + * Enables logging for a bucket. + * + * @param bucketName + * the bucket you wish to enable logging for + * @param logging + * configuration including destination, prefix, and access rules + * @see + */ + void enableBucketLogging(String bucketName, BucketLogging logging); + + /** + * Disables logging for a bucket. + * + * @param bucketName + * the bucket you wish to disable logging for + * + * @see + */ + void disableBucketLogging(String bucketName); } diff --git a/aws/core/src/main/java/org/jclouds/aws/s3/binders/BindACLToXMLPayload.java b/aws/core/src/main/java/org/jclouds/aws/s3/binders/BindACLToXMLPayload.java index 7e827c178a..6524c7109f 100755 --- a/aws/core/src/main/java/org/jclouds/aws/s3/binders/BindACLToXMLPayload.java +++ b/aws/core/src/main/java/org/jclouds/aws/s3/binders/BindACLToXMLPayload.java @@ -42,6 +42,10 @@ import org.jclouds.util.Utils; import com.jamesmurty.utils.XMLBuilder; +/** + * + * @author James Murty + */ public class BindACLToXMLPayload implements Binder { public void bindToRequest(HttpRequest request, Object payload) { diff --git a/aws/core/src/main/java/org/jclouds/aws/s3/binders/BindBucketLoggingToXmlPayload.java b/aws/core/src/main/java/org/jclouds/aws/s3/binders/BindBucketLoggingToXmlPayload.java new file mode 100644 index 0000000000..c57296d70d --- /dev/null +++ b/aws/core/src/main/java/org/jclouds/aws/s3/binders/BindBucketLoggingToXmlPayload.java @@ -0,0 +1,97 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * 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.aws.s3.binders; + +import java.util.Properties; + +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.xml.parsers.FactoryConfigurationError; +import javax.xml.parsers.ParserConfigurationException; + +import org.jclouds.aws.s3.domain.BucketLogging; +import org.jclouds.aws.s3.domain.AccessControlList.CanonicalUserGrantee; +import org.jclouds.aws.s3.domain.AccessControlList.EmailAddressGrantee; +import org.jclouds.aws.s3.domain.AccessControlList.Grant; +import org.jclouds.aws.s3.domain.AccessControlList.GroupGrantee; +import org.jclouds.aws.s3.reference.S3Constants; +import org.jclouds.http.HttpRequest; +import org.jclouds.rest.Binder; +import org.jclouds.util.Utils; + +import com.jamesmurty.utils.XMLBuilder; + +/** + * + * @author Adrian Cole + */ +public class BindBucketLoggingToXmlPayload implements Binder { + + public void bindToRequest(HttpRequest request, Object payload) { + BucketLogging from = (BucketLogging) payload; + Properties outputProperties = new Properties(); + outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes"); + try { + String stringPayload = generateBuilder(from).asString(outputProperties); + request.getHeaders().put(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_XML); + request.getHeaders().put(HttpHeaders.CONTENT_LENGTH, stringPayload.getBytes().length + ""); + request.setPayload(stringPayload); + } catch (Exception e) { + Utils.rethrowIfRuntime(e); + throw new RuntimeException("error transforming bucketLogging: " + from, e); + } + } + + protected XMLBuilder generateBuilder(BucketLogging bucketLogging) + throws ParserConfigurationException, FactoryConfigurationError { + XMLBuilder rootBuilder = XMLBuilder.create("BucketLoggingStatus").attr("xmlns", + S3Constants.S3_REST_API_XML_NAMESPACE).e("LoggingEnabled"); + rootBuilder.e("TargetBucket").t(bucketLogging.getTargetBucket()); + rootBuilder.e("TargetPrefix").t(bucketLogging.getTargetPrefix()); + XMLBuilder grantsBuilder = rootBuilder.elem("TargetGrants"); + for (Grant grant : bucketLogging.getTargetGrants()) { + XMLBuilder grantBuilder = grantsBuilder.elem("Grant"); + XMLBuilder granteeBuilder = grantBuilder.elem("Grantee").attr("xmlns:xsi", + "http://www.w3.org/2001/XMLSchema-instance"); + + if (grant.getGrantee() instanceof GroupGrantee) { + granteeBuilder.attr("xsi:type", "Group").elem("URI").text( + grant.getGrantee().getIdentifier()); + } else if (grant.getGrantee() instanceof CanonicalUserGrantee) { + CanonicalUserGrantee grantee = (CanonicalUserGrantee) grant.getGrantee(); + granteeBuilder.attr("xsi:type", "CanonicalUser").elem("ID").text( + grantee.getIdentifier()).up(); + if (grantee.getDisplayName() != null) { + granteeBuilder.elem("DisplayName").text(grantee.getDisplayName()); + } + } else if (grant.getGrantee() instanceof EmailAddressGrantee) { + granteeBuilder.attr("xsi:type", "AmazonCustomerByEmail").elem("EmailAddress").text( + grant.getGrantee().getIdentifier()); + } + grantBuilder.elem("Permission").text(grant.getPermission().toString()); + } + return grantsBuilder; + } + +} diff --git a/aws/core/src/main/java/org/jclouds/aws/s3/binders/BindNoBucketLoggingToXmlPayload.java b/aws/core/src/main/java/org/jclouds/aws/s3/binders/BindNoBucketLoggingToXmlPayload.java new file mode 100644 index 0000000000..161f88cd3b --- /dev/null +++ b/aws/core/src/main/java/org/jclouds/aws/s3/binders/BindNoBucketLoggingToXmlPayload.java @@ -0,0 +1,45 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * 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.aws.s3.binders; + +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; + +import org.jclouds.http.HttpRequest; +import org.jclouds.rest.Binder; + +/** + * + * @author Adrian Cole + */ +public class BindNoBucketLoggingToXmlPayload implements Binder { + + public void bindToRequest(HttpRequest request, Object payload) { + String stringPayload = ""; + request.getHeaders().put(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_XML); + request.getHeaders().put(HttpHeaders.CONTENT_LENGTH, stringPayload.getBytes().length + ""); + request.setPayload(stringPayload); + } + +} diff --git a/aws/core/src/main/java/org/jclouds/aws/s3/domain/AccessControlList.java b/aws/core/src/main/java/org/jclouds/aws/s3/domain/AccessControlList.java index 44cd2e79d9..e86c1cc783 100755 --- a/aws/core/src/main/java/org/jclouds/aws/s3/domain/AccessControlList.java +++ b/aws/core/src/main/java/org/jclouds/aws/s3/domain/AccessControlList.java @@ -302,6 +302,37 @@ public class AccessControlList { return myGranteeAndPermission.compareTo(otherGranteeAndPermission); } } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((grantee == null) ? 0 : grantee.hashCode()); + result = prime * result + ((permission == null) ? 0 : permission.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Grant other = (Grant) obj; + if (grantee == null) { + if (other.grantee != null) + return false; + } else if (!grantee.equals(other.grantee)) + return false; + if (permission == null) { + if (other.permission != null) + return false; + } else if (!permission.equals(other.permission)) + return false; + return true; + } } public abstract static class Grantee implements Comparable { @@ -327,6 +358,31 @@ public class AccessControlList { public int compareTo(org.jclouds.aws.s3.domain.AccessControlList.Grantee o) { return (this == o) ? 0 : getIdentifier().compareTo(o.getIdentifier()); } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((identifier == null) ? 0 : identifier.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Grantee other = (Grantee) obj; + if (identifier == null) { + if (other.identifier != null) + return false; + } else if (!identifier.equals(other.identifier)) + return false; + return true; + } } public static class EmailAddressGrantee extends Grantee { diff --git a/aws/core/src/main/java/org/jclouds/aws/s3/domain/BucketLogging.java b/aws/core/src/main/java/org/jclouds/aws/s3/domain/BucketLogging.java new file mode 100644 index 0000000000..8c30e71bde --- /dev/null +++ b/aws/core/src/main/java/org/jclouds/aws/s3/domain/BucketLogging.java @@ -0,0 +1,149 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * 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.aws.s3.domain; + +import java.util.Set; + +import org.jclouds.aws.s3.domain.AccessControlList.Grant; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Sets; + +/** + * Each Amazon S3 bucket has an associated XML sub-resource that you can read and write in order to + * inspect or change the logging status for that bucket. + * + * @author Adrian Cole + * @see + */ +public class BucketLogging { + private final String targetBucket; + private final String targetPrefix; + private final Set targetGrants = Sets.newHashSet(); + + /** + * + * @param targetBucket + * {@link #getTargetBucket} + * @param targetPrefix + * {@link #getTargetPrefix} + * @param targetGrants + * {@link #getTargetGrants} + */ + public BucketLogging(String targetBucket, String targetPrefix, Iterable targetGrants) { + this.targetBucket = targetBucket; + this.targetPrefix = targetPrefix; + Iterables.addAll(this.targetGrants, targetGrants); + } + + /** + * + * @param targetBucket + * {@link #getTargetBucket} + * @param targetPrefix + * {@link #getTargetPrefix} + */ + public BucketLogging(String targetBucket, String targetPrefix) { + this.targetBucket = targetBucket; + this.targetPrefix = targetPrefix; + } + + /** + * The bucket owner is automatically granted FULL_CONTROL to all logs delivered to the bucket. + * This optional element enables you grant access to others. Any specified TargetGrants are added + * to the default ACL. For more information about ACLs, see Access Control Lists. + */ + public Set getTargetGrants() { + return targetGrants; + } + + /** + * Specifies the bucket where server access logs will be delivered. You can have your logs + * delivered to any bucket that you own, including the same bucket that is being logged. You can + * also configure multiple buckets to deliver their logs to the same target bucket. In this case + * you should choose a different TargetPrefix for each source bucket so that the delivered log + * files can be distinguished by key. + *

+ *

Note

+ * + * The source and the target buckets must be in the same location. For more information about + * bucket location constraints, see Buckets and Regions + */ + public String getTargetBucket() { + return targetBucket; + } + + /** + * This element lets you specify a prefix for the keys that the delivered log files will be + * stored under. For information on how the key name for log files is constructed, see Delivery + * of Server Access Logs. + */ + public String getTargetPrefix() { + return targetPrefix; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((targetBucket == null) ? 0 : targetBucket.hashCode()); + result = prime * result + ((targetGrants == null) ? 0 : targetGrants.hashCode()); + result = prime * result + ((targetPrefix == null) ? 0 : targetPrefix.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + BucketLogging other = (BucketLogging) obj; + if (targetBucket == null) { + if (other.targetBucket != null) + return false; + } else if (!targetBucket.equals(other.targetBucket)) + return false; + if (targetGrants == null) { + if (other.targetGrants != null) + return false; + } else if (!targetGrants.equals(other.targetGrants)) + return false; + if (targetPrefix == null) { + if (other.targetPrefix != null) + return false; + } else if (!targetPrefix.equals(other.targetPrefix)) + return false; + return true; + } + + @Override + public String toString() { + return "BucketLogging [targetBucket=" + targetBucket + ", targetGrants=" + targetGrants + + ", targetPrefix=" + targetPrefix + "]"; + } + +} diff --git a/aws/core/src/main/java/org/jclouds/aws/s3/xml/BucketLoggingHandler.java b/aws/core/src/main/java/org/jclouds/aws/s3/xml/BucketLoggingHandler.java new file mode 100644 index 0000000000..b4790fd81a --- /dev/null +++ b/aws/core/src/main/java/org/jclouds/aws/s3/xml/BucketLoggingHandler.java @@ -0,0 +1,102 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * 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.aws.s3.xml; + +import java.util.Set; + +import org.jclouds.aws.s3.domain.BucketLogging; +import org.jclouds.aws.s3.domain.AccessControlList.CanonicalUserGrantee; +import org.jclouds.aws.s3.domain.AccessControlList.EmailAddressGrantee; +import org.jclouds.aws.s3.domain.AccessControlList.Grant; +import org.jclouds.aws.s3.domain.AccessControlList.Grantee; +import org.jclouds.aws.s3.domain.AccessControlList.GroupGrantee; +import org.jclouds.aws.s3.domain.AccessControlList.GroupGranteeURI; +import org.jclouds.aws.s3.domain.AccessControlList.Permission; +import org.jclouds.http.functions.ParseSax; +import org.xml.sax.Attributes; + +import com.google.common.collect.Sets; + +/** + * Parses the following XML document: + *

+ * BucketLoggingStatus xmlns="http://s3.amazonaws.com/doc/2006-03-01/" + * + * @author Adrian Cole + * @see + */ +public class BucketLoggingHandler extends ParseSax.HandlerWithResult { + private Set targetGrants = Sets.newHashSet(); + private StringBuilder currentText = new StringBuilder(); + + public BucketLogging getResult() { + if (targetBucket == null) + return null; + return new BucketLogging(targetBucket, targetPrefix, targetGrants); + } + + private String currentId; + private String currentDisplayName; + private String currentGranteeType; + private String currentPermission; + private Grantee currentGrantee; + + private String targetBucket; + private String targetPrefix; + + public void startElement(String uri, String name, String qName, Attributes attrs) { + if (qName.equals("Grantee")) { + currentGranteeType = attrs.getValue("xsi:type"); + } + } + + public void endElement(String uri, String name, String qName) { + if (qName.equals("TargetBucket")) { + this.targetBucket = currentText.toString().trim(); + } else if (qName.equals("TargetPrefix")) { + this.targetPrefix = currentText.toString().trim(); + } else if (qName.equals("Grantee")) { + if ("AmazonCustomerByEmail".equals(currentGranteeType)) { + currentGrantee = new EmailAddressGrantee(currentId); + } else if ("CanonicalUser".equals(currentGranteeType)) { + currentGrantee = new CanonicalUserGrantee(currentId, currentDisplayName); + } else if ("Group".equals(currentGranteeType)) { + currentGrantee = new GroupGrantee(GroupGranteeURI.fromURI(currentId)); + } + } else if (qName.equals("Grant")) { + targetGrants.add(new Grant(currentGrantee, Permission.valueOf(currentPermission))); + } else if (qName.equals("ID") || qName.equals("EmailAddress") || qName.equals("URI")) { + currentId = currentText.toString().trim(); + } else if (qName.equals("DisplayName")) { + currentDisplayName = currentText.toString().trim(); + } else if (qName.equals("Permission")) { + currentPermission = currentText.toString().trim(); + } + currentText = new StringBuilder(); + } + + public void characters(char ch[], int start, int length) { + currentText.append(ch, start, length); + } +} diff --git a/aws/core/src/test/java/org/jclouds/aws/s3/S3AsyncClientTest.java b/aws/core/src/test/java/org/jclouds/aws/s3/S3AsyncClientTest.java index 9d0a48144e..92da5ff25f 100644 --- a/aws/core/src/test/java/org/jclouds/aws/s3/S3AsyncClientTest.java +++ b/aws/core/src/test/java/org/jclouds/aws/s3/S3AsyncClientTest.java @@ -33,9 +33,13 @@ import java.net.URI; import org.jclouds.aws.s3.blobstore.functions.BlobToObject; import org.jclouds.aws.s3.config.S3ObjectModule; import org.jclouds.aws.s3.domain.AccessControlList; +import org.jclouds.aws.s3.domain.BucketLogging; import org.jclouds.aws.s3.domain.CannedAccessPolicy; import org.jclouds.aws.s3.domain.Payer; import org.jclouds.aws.s3.domain.S3Object; +import org.jclouds.aws.s3.domain.AccessControlList.EmailAddressGrantee; +import org.jclouds.aws.s3.domain.AccessControlList.Grant; +import org.jclouds.aws.s3.domain.AccessControlList.Permission; import org.jclouds.aws.s3.filters.RequestAuthorizeSignature; import org.jclouds.aws.s3.functions.ParseObjectFromHeadersAndHttpContent; import org.jclouds.aws.s3.functions.ParseObjectMetadataFromHeaders; @@ -47,6 +51,7 @@ import org.jclouds.aws.s3.options.PutBucketOptions; import org.jclouds.aws.s3.options.PutObjectOptions; import org.jclouds.aws.s3.reference.S3Constants; import org.jclouds.aws.s3.xml.AccessControlListHandler; +import org.jclouds.aws.s3.xml.BucketLoggingHandler; import org.jclouds.aws.s3.xml.CopyObjectHandler; import org.jclouds.aws.s3.xml.ListAllMyBucketsHandler; import org.jclouds.aws.s3.xml.ListBucketHandler; @@ -71,9 +76,11 @@ import org.jclouds.rest.RestClientTest; import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.RestAnnotationProcessor; import org.jclouds.util.Jsr330; +import org.jclouds.util.Utils; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import com.google.common.collect.ImmutableSet; import com.google.inject.AbstractModule; import com.google.inject.Module; import com.google.inject.Provides; @@ -407,6 +414,60 @@ public class S3AsyncClientTest extends RestClientTest { checkFilters(httpMethod); } + public void testGetBucketLogging() throws SecurityException, NoSuchMethodException, IOException { + Method method = S3AsyncClient.class.getMethod("getBucketLogging", String.class); + GeneratedHttpRequest httpMethod = processor.createRequest(method, "bucket"); + + assertRequestLineEquals(httpMethod, "GET http://bucket.stub:8080/?logging HTTP/1.1"); + assertHeadersEqual(httpMethod, "Host: bucket.stub\n"); + assertPayloadEquals(httpMethod, null); + + assertResponseParserClassEquals(method, httpMethod, ParseSax.class); + assertSaxResponseParserClassEquals(method, BucketLoggingHandler.class); + assertExceptionParserClassEquals(method, ThrowContainerNotFoundOn404.class); + + checkFilters(httpMethod); + } + + public void testDisableBucketLogging() throws SecurityException, NoSuchMethodException, + IOException { + Method method = S3AsyncClient.class.getMethod("disableBucketLogging", String.class); + GeneratedHttpRequest httpMethod = processor.createRequest(method, "bucket"); + + assertRequestLineEquals(httpMethod, "PUT http://bucket.stub:8080/?logging HTTP/1.1"); + assertHeadersEqual(httpMethod, + "Content-Length: 70\nContent-Type: text/xml\nHost: bucket.stub\n"); + assertPayloadEquals(httpMethod, + ""); + + assertResponseParserClassEquals(method, httpMethod, ReturnVoidIf2xx.class); + assertSaxResponseParserClassEquals(method, null); + assertExceptionParserClassEquals(method, null); + + checkFilters(httpMethod); + } + + public void testEnableBucketLoggingOwner() throws SecurityException, NoSuchMethodException, + IOException { + Method method = S3AsyncClient.class.getMethod("enableBucketLogging", String.class, + BucketLogging.class); + GeneratedHttpRequest httpMethod = processor.createRequest(method, "bucket", + new BucketLogging("mylogs", "access_log-", ImmutableSet. of(new Grant( + new EmailAddressGrantee("adrian@jclouds.org"), Permission.FULL_CONTROL)))); + + assertRequestLineEquals(httpMethod, "PUT http://bucket.stub:8080/?logging HTTP/1.1"); + assertHeadersEqual(httpMethod, + "Content-Length: 433\nContent-Type: text/xml\nHost: bucket.stub\n"); + assertPayloadEquals(httpMethod, Utils.toStringAndClose(getClass().getResourceAsStream( + "/s3/bucket_logging.xml"))); + + assertResponseParserClassEquals(method, httpMethod, ReturnVoidIf2xx.class); + assertSaxResponseParserClassEquals(method, null); + assertExceptionParserClassEquals(method, null); + + checkFilters(httpMethod); + } + BlobToObject blobToS3Object; @Override diff --git a/aws/core/src/test/java/org/jclouds/aws/s3/binders/BindBucketLoggingToXmlPayloadTest.java b/aws/core/src/test/java/org/jclouds/aws/s3/binders/BindBucketLoggingToXmlPayloadTest.java new file mode 100644 index 0000000000..9ee0cadd96 --- /dev/null +++ b/aws/core/src/test/java/org/jclouds/aws/s3/binders/BindBucketLoggingToXmlPayloadTest.java @@ -0,0 +1,48 @@ +package org.jclouds.aws.s3.binders; + +import static org.testng.Assert.assertEquals; + +import java.io.IOException; +import java.net.URI; + +import javax.ws.rs.core.HttpHeaders; + +import org.jclouds.aws.s3.domain.BucketLogging; +import org.jclouds.aws.s3.domain.AccessControlList.EmailAddressGrantee; +import org.jclouds.aws.s3.domain.AccessControlList.Grant; +import org.jclouds.aws.s3.domain.AccessControlList.Permission; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.functions.BaseHandlerTest; +import org.jclouds.util.Utils; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; + +/** + * Tests behavior of {@code BindBucketLoggingToXmlPayload} + * + * @author Adrian Cole + */ +@Test(groups = "unit", testName = "s3.BindBucketLoggingToXmlPayloadTest") +public class BindBucketLoggingToXmlPayloadTest extends BaseHandlerTest { + + public void testApplyInputStream() throws IOException { + + BucketLogging bucketLogging = new BucketLogging("mylogs", "access_log-", ImmutableSet + . of(new Grant(new EmailAddressGrantee("adrian@jclouds.org"), + Permission.FULL_CONTROL))); + + String expected = Utils.toStringAndClose(getClass().getResourceAsStream( + "/s3/bucket_logging.xml")); + + HttpRequest request = new HttpRequest("GET", URI.create("http://test")); + BindBucketLoggingToXmlPayload binder = injector + .getInstance(BindBucketLoggingToXmlPayload.class); + + binder.bindToRequest(request, bucketLogging); + assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE), "text/xml"); + assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH), "433"); + assertEquals(request.getPayload().getRawContent(), expected); + + } +} diff --git a/aws/core/src/test/java/org/jclouds/aws/s3/binders/BindNoBucketLoggingToXmlPayloadTest.java b/aws/core/src/test/java/org/jclouds/aws/s3/binders/BindNoBucketLoggingToXmlPayloadTest.java new file mode 100644 index 0000000000..b032ab0259 --- /dev/null +++ b/aws/core/src/test/java/org/jclouds/aws/s3/binders/BindNoBucketLoggingToXmlPayloadTest.java @@ -0,0 +1,35 @@ +package org.jclouds.aws.s3.binders; + +import static org.testng.Assert.assertEquals; + +import java.io.IOException; +import java.net.URI; + +import javax.ws.rs.core.HttpHeaders; + +import org.jclouds.http.HttpRequest; +import org.jclouds.http.functions.BaseHandlerTest; +import org.testng.annotations.Test; + +/** + * Tests behavior of {@code BindNoBucketLoggingToXmlPayload} + * + * @author Adrian Cole + */ +@Test(groups = "unit", testName = "s3.BindNoBucketLoggingToXmlPayloadTest") +public class BindNoBucketLoggingToXmlPayloadTest extends BaseHandlerTest { + + public void testApplyInputStream() throws IOException { + + HttpRequest request = new HttpRequest("GET", URI.create("http://test")); + BindNoBucketLoggingToXmlPayload binder = injector + .getInstance(BindNoBucketLoggingToXmlPayload.class); + + binder.bindToRequest(request, null); + assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE), "text/xml"); + assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH), "70"); + assertEquals(request.getPayload().getRawContent(), + ""); + + } +} diff --git a/aws/core/src/test/java/org/jclouds/aws/s3/internal/StubS3AsyncClient.java b/aws/core/src/test/java/org/jclouds/aws/s3/internal/StubS3AsyncClient.java index 44296b44e3..1b8084b7a0 100755 --- a/aws/core/src/test/java/org/jclouds/aws/s3/internal/StubS3AsyncClient.java +++ b/aws/core/src/test/java/org/jclouds/aws/s3/internal/StubS3AsyncClient.java @@ -43,6 +43,7 @@ import org.jclouds.aws.s3.blobstore.functions.BucketToContainerListOptions; import org.jclouds.aws.s3.blobstore.functions.ObjectToBlob; import org.jclouds.aws.s3.blobstore.functions.ResourceToBucketList; import org.jclouds.aws.s3.domain.AccessControlList; +import org.jclouds.aws.s3.domain.BucketLogging; import org.jclouds.aws.s3.domain.BucketMetadata; import org.jclouds.aws.s3.domain.CannedAccessPolicy; import org.jclouds.aws.s3.domain.ListBucketResponse; @@ -363,4 +364,31 @@ public class StubS3AsyncClient implements S3AsyncClient { }; } + @Override + public Future disableBucketLogging(String bucketName) { + return new FutureBase() { + public Void get() throws InterruptedException, ExecutionException { + return null; + } + }; + } + + @Override + public Future enableBucketLogging(String bucketName, BucketLogging logging) { + return new FutureBase() { + public Void get() throws InterruptedException, ExecutionException { + return null; + } + }; + } + + @Override + public Future getBucketLogging(String bucketName) { + return new FutureBase() { + public BucketLogging get() throws InterruptedException, ExecutionException { + return null; + } + }; + } + } diff --git a/aws/core/src/test/java/org/jclouds/aws/s3/services/BucketsLiveTest.java b/aws/core/src/test/java/org/jclouds/aws/s3/services/BucketsLiveTest.java index cec759eca5..94013d5005 100644 --- a/aws/core/src/test/java/org/jclouds/aws/s3/services/BucketsLiveTest.java +++ b/aws/core/src/test/java/org/jclouds/aws/s3/services/BucketsLiveTest.java @@ -30,7 +30,7 @@ import static org.jclouds.aws.s3.options.ListBucketOptions.Builder.withPrefix; import static org.jclouds.aws.s3.options.PutBucketOptions.Builder.createIn; import static org.jclouds.aws.s3.options.PutBucketOptions.Builder.withBucketAcl; import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import static org.testng.Assert.*; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -43,6 +43,7 @@ import java.util.concurrent.TimeoutException; import org.jclouds.aws.s3.S3AsyncClient; import org.jclouds.aws.s3.S3Client; import org.jclouds.aws.s3.domain.AccessControlList; +import org.jclouds.aws.s3.domain.BucketLogging; import org.jclouds.aws.s3.domain.BucketMetadata; import org.jclouds.aws.s3.domain.CannedAccessPolicy; import org.jclouds.aws.s3.domain.ListBucketResponse; @@ -50,6 +51,7 @@ import org.jclouds.aws.s3.domain.Payer; import org.jclouds.aws.s3.domain.S3Object; import org.jclouds.aws.s3.domain.AccessControlList.CanonicalUserGrantee; import org.jclouds.aws.s3.domain.AccessControlList.EmailAddressGrantee; +import org.jclouds.aws.s3.domain.AccessControlList.Grant; import org.jclouds.aws.s3.domain.AccessControlList.GroupGranteeURI; import org.jclouds.aws.s3.domain.AccessControlList.Permission; import org.jclouds.aws.s3.domain.BucketMetadata.LocationConstraint; @@ -58,6 +60,8 @@ import org.jclouds.blobstore.integration.internal.BaseBlobStoreIntegrationTest; import org.jclouds.util.Utils; import org.testng.annotations.Test; +import com.google.common.collect.ImmutableSet; + /** * * @author James Murty @@ -213,6 +217,64 @@ public class BucketsLiveTest extends BaseBlobStoreIntegrationTest of(new Grant(new EmailAddressGrantee(StubS3AsyncClient.TEST_ACL_EMAIL), + Permission.FULL_CONTROL))); + + context.getApi().enableBucketLogging(bucketName, logging); + + assertConsistencyAware(new Runnable() { + public void run() { + try { + BucketLogging newLogging = context.getApi().getBucketLogging(bucketName); + AccessControlList acl = new AccessControlList(); + for (Grant grant : newLogging.getTargetGrants()) { // TODO: add permission + // checking features to + // bucketlogging + acl.addPermission(grant.getGrantee(), grant.getPermission()); + } + // EmailAddressGrantee is replaced by a CanonicalUserGrantee, so we cannot test by + // email addr + assertTrue(acl.hasPermission(StubS3AsyncClient.TEST_ACL_ID, + Permission.FULL_CONTROL), acl.toString()); + assertEquals(logging.getTargetBucket(), newLogging.getTargetBucket()); + assertEquals(logging.getTargetPrefix(), newLogging.getTargetPrefix()); + } catch (Exception e) { + Utils. rethrowIfRuntimeOrSameType(e); + } + } + }); + context.getApi().disableBucketLogging(bucketName); + assertConsistencyAware(new Runnable() { + public void run() { + try { + assertNull(context.getApi().getBucketLogging(bucketName)); + } catch (Exception e) { + Utils. rethrowIfRuntimeOrSameType(e); + } + } + }); + } finally { + destroyContainer(bucketName); + destroyContainer(targetBucket); + } + } + + private void setupAclForBucketLoggingTarget(final String targetBucket) { + // http://docs.amazonwebservices.com/AmazonS3/latest/LoggingHowTo.html + AccessControlList acl = context.getApi().getBucketACL(targetBucket); + acl.addPermission(GroupGranteeURI.LOG_DELIVERY, Permission.WRITE); + acl.addPermission(GroupGranteeURI.LOG_DELIVERY, Permission.READ_ACP); + assertTrue(context.getApi().putBucketACL(targetBucket, acl)); + } + /** * using scratch bucketName as we are changing location */ diff --git a/aws/core/src/test/java/org/jclouds/aws/s3/xml/BucketLoggingHandlerTest.java b/aws/core/src/test/java/org/jclouds/aws/s3/xml/BucketLoggingHandlerTest.java new file mode 100644 index 0000000000..d91983a07a --- /dev/null +++ b/aws/core/src/test/java/org/jclouds/aws/s3/xml/BucketLoggingHandlerTest.java @@ -0,0 +1,61 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * 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.aws.s3.xml; + +import static org.testng.Assert.assertEquals; + +import java.io.InputStream; + +import org.jclouds.aws.s3.domain.BucketLogging; +import org.jclouds.aws.s3.domain.AccessControlList.EmailAddressGrantee; +import org.jclouds.aws.s3.domain.AccessControlList.Grant; +import org.jclouds.aws.s3.domain.AccessControlList.Permission; +import org.jclouds.http.functions.BaseHandlerTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; + +/** + * Tests behavior of {@code BucketLoggingHandler} + * + * @author Adrian Cole + */ +@Test(groups = "unit", testName = "ec2.BucketLoggingHandlerTest") +public class BucketLoggingHandlerTest extends BaseHandlerTest { + public void testApplyInputStream() { + InputStream is = getClass().getResourceAsStream("/s3/bucket_logging.xml"); + + BucketLogging expected = new BucketLogging("mylogs", "access_log-", ImmutableSet + . of(new Grant(new EmailAddressGrantee("adrian@jclouds.org"), + Permission.FULL_CONTROL))); + BucketLoggingHandler handler = injector.getInstance(BucketLoggingHandler.class); + BucketLogging result = factory.create(handler).parse(is); + + assertEquals(result.getTargetBucket(), expected.getTargetBucket()); + assertEquals(result.getTargetGrants(), expected.getTargetGrants()); + assertEquals(result.getTargetPrefix(), expected.getTargetPrefix()); + + } + +} \ No newline at end of file diff --git a/aws/core/src/test/resources/s3/bucket_logging.xml b/aws/core/src/test/resources/s3/bucket_logging.xml new file mode 100644 index 0000000000..9eb5239815 --- /dev/null +++ b/aws/core/src/test/resources/s3/bucket_logging.xml @@ -0,0 +1 @@ +mylogsaccess_log-adrian@jclouds.orgFULL_CONTROL \ No newline at end of file