/************************************************************************* * Copyright 2013-2014 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.client; import java.util.Date; import javax.annotation.Nonnull; import com.amazonaws.ClientConfiguration; import com.amazonaws.Protocol; import com.amazonaws.auth.AWSCredentials; import com.amazonaws.services.s3.AmazonS3Client; import com.amazonaws.services.s3.S3ClientOptions; /** * A convenience wrapper for an AWS Java SDK S3 Client that sets default timeouts etc, options, etc * * This is specifically as needed for the OSG's internal use to various backends */ public class OsgInternalS3Client { private static final int CONNECTION_TIMEOUT_MS = 500; // 500ms connection timeout, fail fast private static final int OSG_SOCKET_TIMEOUT_MS = 10 * 1000; // 10 sec socket timeout if no data private static final int OSG_MAX_CONNECTIONS = 512; // Lots of connections since this is for the whole OSG private static final String SIGNER_OVERRIDE = System.getProperty( "com.eucalyptus.objectstorage.client.signerType", "S3SignerType" ); private S3ClientOptions ops; private AmazonS3Client s3Client; private ClientConfiguration clientConfig; private Date instantiated; private volatile String endpoint; private volatile AWSCredentials currentCredentials; public OsgInternalS3Client(AWSCredentials credentials, String endpoint, boolean https, boolean useDns) { update(credentials, endpoint, https, useDns); } public void setUsePathStyle(boolean usePathStyle) { ops.setPathStyleAccess(usePathStyle); s3Client.setS3ClientOptions(ops); } public AmazonS3Client getS3Client() { return s3Client; } public synchronized String getS3Endpoint() { return this.endpoint; } public synchronized void setS3Endpoint(String s3Endpoint) { this.endpoint = s3Endpoint; s3Client.setEndpoint(s3Endpoint); } /** * Basically an .equals() call for AWSCreds * * @param c1 * @param c2 * @return */ private static boolean credentialsEqual(AWSCredentials c1, AWSCredentials c2) { return (c1 == null && c2 == null) || (c1 == null || c2 == null) || (c1.getAWSSecretKey() != null && c1.getAWSSecretKey().equals(c2.getAWSSecretKey()) && c1.getAWSAccessKeyId() != null && c1 .getAWSAccessKeyId().equals(c2.getAWSAccessKeyId())); } private synchronized void initializeNewClient(@Nonnull AWSCredentials credentials, @Nonnull String endpoint, @Nonnull Boolean https, @Nonnull Boolean useDns) { ClientConfiguration config = new ClientConfiguration(); config.setConnectionTimeout(CONNECTION_TIMEOUT_MS); // very short timeout config.setSocketTimeout(OSG_SOCKET_TIMEOUT_MS); config.setUseReaper(true); config.setMaxConnections(OSG_MAX_CONNECTIONS); Protocol protocol = https ? Protocol.HTTPS : Protocol.HTTP; config.setProtocol(protocol); config.setSignerOverride(SIGNER_OVERRIDE); this.clientConfig = config; this.s3Client = new AmazonS3Client(credentials, config); this.ops = new S3ClientOptions().withPathStyleAccess(!useDns); this.s3Client.setS3ClientOptions(ops); this.instantiated = new Date(); this.currentCredentials = credentials; this.setS3Endpoint(endpoint); } public void update(@Nonnull AWSCredentials credentials, @Nonnull String latestEndpoint, @Nonnull Boolean https, @Nonnull Boolean useDns) { // Credentials changes require new client instance (for now) if (this.s3Client == null || !credentialsEqual(this.currentCredentials, credentials)) { this.initializeNewClient(credentials, latestEndpoint, https, useDns); return; } // They have opposite semantics, so any equality means it must be updated if (this.ops.isPathStyleAccess() == useDns) { this.ops.setPathStyleAccess(!useDns); this.s3Client.setS3ClientOptions(this.ops); } Protocol tmpProto = https ? Protocol.HTTPS : Protocol.HTTP; if (!tmpProto.equals(this.clientConfig.getProtocol())) { this.clientConfig.setProtocol(tmpProto); } if (this.getS3Endpoint() == null || !this.getS3Endpoint().equals(latestEndpoint)) { this.setS3Endpoint(latestEndpoint); } } public Date getInstantiated() { return instantiated; } }