All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.indix.gocd.utils.store.S3ArtifactStore Maven / Gradle / Ivy

The newest version!
package com.indix.gocd.utils.store;

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.auth.InstanceProfileCredentialsProvider;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;
import com.indix.gocd.models.Artifact;
import com.indix.gocd.models.ResponseMetadataConstants;
import com.indix.gocd.models.Revision;
import com.indix.gocd.models.RevisionStatus;
import com.indix.gocd.utils.GoEnvironment;
import com.indix.gocd.utils.utils.Function;
import com.indix.gocd.utils.utils.Functions;
import com.indix.gocd.utils.utils.Lists;
import com.indix.gocd.utils.utils.Maps;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import static com.indix.gocd.utils.Constants.*;

public class S3ArtifactStore {

    private static Map STORAGE_CLASSES = Maps.builder()
            .with(STORAGE_CLASS_STANDARD, StorageClass.Standard)
            .with(STORAGE_CLASS_STANDARD_IA, StorageClass.StandardInfrequentAccess)
            .with(STORAGE_CLASS_RRS, StorageClass.ReducedRedundancy)
            .with(STORAGE_CLASS_GLACIER, StorageClass.Glacier)
            .build();

    private AmazonS3 client;
    private String bucket;
    private StorageClass storageClass = StorageClass.Standard;

    public S3ArtifactStore(AmazonS3 client, String bucket) {
        this.client = client;
        this.bucket = bucket;
    }

    public S3ArtifactStore(GoEnvironment env, String bucket) {
        this(getS3client(env), bucket);
    }

    public S3ArtifactStore(String bucket) {
        this(getS3client(new GoEnvironment()), bucket);
    }

    public void setStorageClass(String storageClass) {
        String key = StringUtils.lowerCase(storageClass);
        if (STORAGE_CLASSES.containsKey(key)) {
            this.storageClass = STORAGE_CLASSES.get(key);
        } else {
            throw new IllegalArgumentException("Invalid storage class specified for S3 - " + storageClass + ". Accepted values are standard, standard-ia, rrs and glacier");
        }
    }

    public void put(String from, String to) {
        put(new PutObjectRequest(bucket, to, new File(from)));
    }

    public void put(String from, String to, ObjectMetadata metadata) {
        put(new PutObjectRequest(bucket, to, new File(from))
                .withMetadata(metadata));
    }

    public void put(PutObjectRequest putObjectRequest) {
        putObjectRequest.setStorageClass(this.storageClass);
        client.putObject(putObjectRequest);
    }

    public String pathString(String pathOnS3) {
        return String.format("s3://%s/%s", bucket, pathOnS3);
    }

    public void get(String from, String to) {
        GetObjectRequest getObjectRequest = new GetObjectRequest(bucket, from);
        File destinationFile = new File(to);
        destinationFile.getParentFile().mkdirs();
        client.getObject(getObjectRequest, destinationFile);
    }

    public ObjectMetadata getMetadata(String key) {
        return client.getObjectMetadata(bucket, key);
    }

    public void getPrefix(String prefix, String to) {
        ListObjectsRequest listObjectsRequest = new ListObjectsRequest()
                .withBucketName(bucket)
                .withPrefix(prefix);

        ObjectListing objectListing;
        do {
            objectListing = client.listObjects(listObjectsRequest);
            for (S3ObjectSummary objectSummary : objectListing.getObjectSummaries()) {
                String destinationPath = to + "/" + objectSummary.getKey().replace(prefix + "/", "");
                long size = objectSummary.getSize();
                if (size > 0) {
                    get(objectSummary.getKey(), destinationPath);
                }
            }
            listObjectsRequest.setMarker(objectListing.getNextMarker());
        } while (objectListing.isTruncated());

    }

    public boolean bucketExists() {
        try {
            client.listObjects(new ListObjectsRequest(bucket, null, null, null, 0));
            return true;
        } catch (Exception ex) {
            return false;
        }
    }

    public boolean exists(String bucket, String key) {
        ListObjectsRequest listObjectsRequest = new ListObjectsRequest()
                .withBucketName(bucket)
                .withPrefix(key)
                .withDelimiter("/");
        try {
            ObjectListing objectListing = client.listObjects(listObjectsRequest);
            return objectListing != null && objectListing.getCommonPrefixes().size() > 0;
        } catch (Exception ex) {
            return false;
        }
    }

    private Boolean isComplete(String prefix) {
        return client.getObjectMetadata(bucket, prefix).getUserMetadata().containsKey(ResponseMetadataConstants.COMPLETED);
    }

    private Revision mostRecentRevision(ObjectListing listing) {
        List prefixes = Lists.filter(listing.getCommonPrefixes(), new Functions.Predicate() {
            @Override
            public Boolean execute(String input) {
                return isComplete(input);
            }
        });

        List revisions = Lists.map(prefixes, new Function() {
            @Override
            public Revision apply(String prefix) {
                String[] parts = prefix.split("/");
                String last = parts[parts.length - 1];
                return new Revision(last);
            }
        });

        if (revisions.size() > 0)
            return Collections.max(revisions);
        else
            return Revision.base();
    }

    private Revision latestOfInternal(ObjectListing listing, Revision latestSoFar) {
        if (!listing.isTruncated()) {
            return latestSoFar;
        } else {
            ObjectListing objects = client.listNextBatchOfObjects(listing);
            Revision mostRecent = mostRecentRevision(objects);
            if (latestSoFar.compareTo(mostRecent) > 0)
                mostRecent = latestSoFar;
            return latestOfInternal(objects, mostRecent);
        }
    }

    private Revision latestOf(ObjectListing listing) {
        return latestOfInternal(listing, mostRecentRevision(listing));
    }

    public RevisionStatus getLatest(Artifact artifact) {
        ListObjectsRequest listObjectsRequest = new ListObjectsRequest()
                .withBucketName(bucket)
                .withPrefix(artifact.prefix())
                .withDelimiter("/");

        ObjectListing listing = client.listObjects(listObjectsRequest);
        if (listing != null) {
            Revision recent = latestOf(listing);
            Artifact artifactWithRevision = artifact.withRevision(recent);
            GetObjectMetadataRequest objectMetadataRequest = new GetObjectMetadataRequest(bucket, artifactWithRevision.prefixWithRevision());
            ObjectMetadata metadata = client.getObjectMetadata(objectMetadataRequest);
            Map userMetadata = metadata.getUserMetadata();
            String tracebackUrl = userMetadata.get(ResponseMetadataConstants.TRACEBACK_URL);
            String user = userMetadata.get(ResponseMetadataConstants.USER);
            String revisionLabel = userMetadata.containsKey(ResponseMetadataConstants.GO_PIPELINE_LABEL) ?
                    userMetadata.get(ResponseMetadataConstants.GO_PIPELINE_LABEL)
                    : "";
            return new RevisionStatus(recent, metadata.getLastModified(), tracebackUrl, user, revisionLabel);
        }
        return null;
    }

    public String getLatestPrefix(String pipeline, String stage, String job, String pipelineCounter) {
        String prefix = String.format("%s/%s/%s/%s.", pipeline, stage, job, pipelineCounter);
        ListObjectsRequest listObjectsRequest = new ListObjectsRequest()
                .withBucketName(bucket)
                .withPrefix(prefix)
                .withDelimiter("/");

        ObjectListing listing = client.listObjects(listObjectsRequest);

        if (listing != null) {
            List commonPrefixes = listing.getCommonPrefixes();
            List stageCounters = Lists.map(commonPrefixes,
                    input ->
                            input.replaceAll(prefix, "").replaceAll("/", ""));
            if (stageCounters.size() > 0) {
                int maxStageCounter = Integer.valueOf(stageCounters.get(0));

                for (int i = 1; i < stageCounters.size(); i++) {
                    int stageCounter = Integer.valueOf(stageCounters.get(i));
                    if (stageCounter > maxStageCounter) {
                        maxStageCounter = stageCounter;
                    }
                }

                return prefix + maxStageCounter;
            }
        }
        return null;
    }

    public static AmazonS3 getS3client(GoEnvironment env) {
        AmazonS3ClientBuilder amazonS3ClientBuilder = AmazonS3ClientBuilder.standard();

        if (env.has(AWS_REGION)) {
            amazonS3ClientBuilder.withRegion(env.get(AWS_REGION));
        }
        if (env.hasAWSUseIamRole()) {
            amazonS3ClientBuilder.withCredentials(new InstanceProfileCredentialsProvider(false));
        } else if (env.has(AWS_ACCESS_KEY_ID) && env.has(AWS_SECRET_ACCESS_KEY)) {
            BasicAWSCredentials basicCreds = new BasicAWSCredentials(env.get(AWS_ACCESS_KEY_ID), env.get(AWS_SECRET_ACCESS_KEY));
            amazonS3ClientBuilder.withCredentials(new AWSStaticCredentialsProvider(basicCreds));
        }

        return amazonS3ClientBuilder.build();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy