/************************************************************************* * Copyright 2009-2013 Eucalyptus Systems, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta * CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need * additional information or have any questions. ************************************************************************/ package com.eucalyptus.objectstorage.entities; import java.util.UUID; import javax.annotation.Nonnull; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.Lob; import javax.persistence.PersistenceContext; import javax.persistence.PrePersist; import javax.persistence.Table; import org.hibernate.annotations.Type; import com.eucalyptus.objectstorage.BucketState; import com.eucalyptus.objectstorage.util.ObjectStorageProperties; import com.eucalyptus.objectstorage.util.ObjectStorageProperties.VersioningStatus; import com.eucalyptus.storage.common.DateFormatter; import com.eucalyptus.storage.msgs.s3.AccessControlPolicy; import com.eucalyptus.storage.msgs.s3.BucketListEntry; @Entity @PersistenceContext(name = "eucalyptus_osg") @Table(name = "buckets") public class Bucket extends S3AccessControlledEntity<BucketState> implements Comparable { /** * */ private static final long serialVersionUID = 1L; @Column(name = "bucket_name", unique = true, nullable = true) private String bucketName; // The bucket name as seen by users via S3 API @Column(name = "bucket_uuid", unique = true, nullable = false) private String bucketUuid; // The bucket id used by the backend to ensure uniqueness for lifecycle @Column(name = "bucket_location") private String location; // Is Bucket logging enabled? @Column(name = "logging_enabled") private Boolean loggingEnabled; // If logging enabled, this is the target bucket for logs @Column(name = "target_bucket") private String targetBucket; // If logging enabled, this is the prefix for log objects @Column(name = "target_prefix") private String targetPrefix; @Column(name = "versioning") @Enumerated(EnumType.STRING) private VersioningStatus versioning; // Needed for enforcing IAM size quotas, to prevent having to scan all objects @Column(name = "bucket_size") private Long bucketSize; @Column(name = "policy") @Lob @Type(type="org.hibernate.type.StringClobType") private String policy; @PrePersist public void checkPrePersist() { if (this.getState() == null) { throw new RuntimeException("Unspecified state"); } if (versioning == null) { versioning = VersioningStatus.Disabled; } if (bucketSize == null) { bucketSize = 0L; } if (bucketUuid == null) { genIds(this.getBucketName()); } } /** * Returns an initialized Bucket ready for persistence * * @param name * @param canonicalId * @param displayName * @param iamUserId * @param acl * @param location * @return */ public static Bucket getInitializedBucket(@Nonnull String name, @Nonnull String canonicalId, @Nonnull String displayName, @Nonnull String iamUserId, @Nonnull String acl, @Nonnull String location) { Bucket newBucket = new Bucket(name); newBucket.setOwnerCanonicalId(canonicalId); newBucket.setOwnerDisplayName(displayName); newBucket.setOwnerIamUserId(iamUserId); newBucket.setBucketSize(0L); newBucket.setAcl(acl); newBucket.setLocation(location); newBucket.setLoggingEnabled(false); newBucket.setState(BucketState.creating); newBucket.setVersioning(ObjectStorageProperties.VersioningStatus.Disabled); newBucket.genIds(name); return newBucket; } /** * Returns and initialized Bucket ready for persistence Expects a fully configured AccessControlPolicy with populated owner canonicalId and * displayName * * @param name * @param iamUserId * @param acp * @param location * @return */ public static Bucket getInitializedBucket(@Nonnull String name, @Nonnull String iamUserId, @Nonnull AccessControlPolicy acp, @Nonnull String location) { if (acp.getOwner() == null || acp.getOwner().getID() == null || acp.getOwner().getDisplayName() == null) { throw new IllegalArgumentException("AccessControlPolicy must include full owner id and name"); } Bucket newBucket = new Bucket(name); newBucket.setOwnerCanonicalId(acp.getOwner().getID()); newBucket.setOwnerDisplayName(acp.getOwner().getDisplayName()); newBucket.setOwnerIamUserId(iamUserId); newBucket.setBucketSize(0L); newBucket.setAcl(acp); newBucket.setLocation(location); newBucket.setLoggingEnabled(false); newBucket.setState(BucketState.creating); newBucket.setVersioning(ObjectStorageProperties.VersioningStatus.Disabled); newBucket.genIds(name); return newBucket; } public String getBucketUuid() { return this.bucketUuid; } /** * Sets the bucket UUID directly. INTERNAL USE only! * * @param bucketUuid */ void setBucketUuid(String bucketUuid) { this.bucketUuid = bucketUuid; } private void genIds(@Nonnull String bucketName) { setBucketUuid(UUID.randomUUID().toString()); } public boolean stateStillValid(int stateTimeoutSeconds) { if (getState() != null && !BucketState.creating.equals(getState())) { // extant and deleting states are always valid return true; } else if (getState() == null) { return false; } else { try { return (System.currentTimeMillis() - this.getLastUpdateTimestamp().getTime()) <= ((long) stateTimeoutSeconds * 1000l); } catch (Throwable e) { return true; // Err on side of keeping the bucket rather than flushing it if there is an error in lookup. } } } /** * This is the method to be used to generate example bucket entities for searches * * @param bucketUuid * @return */ public Bucket withUuid(String bucketUuid) { this.setBucketUuid(bucketUuid); return this; } /** * Should *not* be used for modifying the state of a real record. Only for search examples. * <p/> * Modifies the state but does not update the 'lastState'. This is intended for search operations where an example object is needed. * * @param s * @return */ public Bucket withState(BucketState s) { this.setState(s); this.setLastState(null); return this; } public Long getBucketSize() { return bucketSize; } public void setBucketSize(Long bucketSize) { this.bucketSize = bucketSize; } public String generateObjectVersionId() { if (ObjectStorageProperties.VersioningStatus.Enabled.equals(this.getVersioning())) { return UUID.randomUUID().toString().replaceAll("-", ""); } else { return ObjectStorageProperties.NULL_VERSION_ID; } } @Override public String getResourceFullName() { return getBucketName(); } public Bucket() {} public Bucket(@Nonnull String bucketName) { this.bucketName = bucketName; } public Bucket(String ownerId, String ownerIamUserId, String bucketName) { this.genIds(bucketName); setOwnerCanonicalId(ownerId); setOwnerIamUserId(ownerIamUserId); } public String getBucketName() { return this.bucketName; } public void setBucketName(String bucketName) { this.bucketName = bucketName; } public boolean hasLoggingPerms() { // Logging requires write and readACP return this.can(ObjectStorageProperties.Permission.READ_ACP, ObjectStorageProperties.S3_GROUP.LOGGING_GROUP.toString()) && this.can(ObjectStorageProperties.Permission.WRITE, ObjectStorageProperties.S3_GROUP.LOGGING_GROUP.toString()); } public boolean isOwnedBy(String canonicalId) { return this.getOwnerCanonicalId() != null && this.getOwnerCanonicalId().equals(canonicalId); } public String getLocation() { return location; } public void setLocation(String location) { this.location = location; } public Boolean getLoggingEnabled() { return loggingEnabled; } public void setLoggingEnabled(Boolean loggingEnabled) { this.loggingEnabled = loggingEnabled; } public String getTargetBucket() { return targetBucket; } public void setTargetBucket(String targetBucket) { this.targetBucket = targetBucket; } public String getTargetPrefix() { return targetPrefix; } public void setTargetPrefix(String targetPrefix) { this.targetPrefix = targetPrefix; } public VersioningStatus getVersioning() { return versioning; } public void setVersioning(VersioningStatus versioning) { this.versioning = versioning; } public String getPolicy( ) { return policy; } public void setPolicy( final String policy ) { this.policy = policy; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((bucketUuid == null) ? 0 : bucketUuid.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; Bucket other = (Bucket) obj; if (bucketUuid == null) { if (other.bucketUuid != null) return false; } else if (!bucketUuid.equals(other.bucketUuid)) { return false; } return true; } @Override public String toString() { return "[BucketName: " + this.getBucketName() + " , BucketUuid: " + this.getBucketUuid() + " , State: " + this.getState() + " , Size: " + this.getBucketSize() + ", Location: " + this.getLocation() + " , VersioningState: " + this.getVersion() + " , LoggingEnabled: " + this.getLoggingEnabled() + " , AclString: " + this.getAcl() + "]"; } public BucketListEntry toBucketListEntry() { return new BucketListEntry(this.getBucketName(), DateFormatter.dateToListingFormattedString(this.getCreationTimestamp())); } @Override public int compareTo(Object o) { if (o instanceof Bucket) { Bucket other = (Bucket) o; return this.getBucketName().compareTo(((Bucket) o).getBucketName()); } return 0; } }