View Javadoc
1   package org.kuali.common.devops.jenkins.upgrade;
2   
3   import static com.google.common.base.Optional.absent;
4   import static com.google.common.base.Stopwatch.createStarted;
5   import static com.google.common.collect.Iterables.concat;
6   import static com.google.common.collect.Lists.newArrayList;
7   import static java.lang.String.format;
8   import static org.apache.commons.lang.StringUtils.removeStart;
9   import static org.kuali.common.devops.archive.sweep.Functions.allParentsAsListSingle;
10  import static org.kuali.common.devops.archive.sweep.Functions.hostnameToKey;
11  import static org.kuali.common.devops.jenkins.upgrade.S3.sumFileObjects;
12  import static org.kuali.common.util.FormatUtils.getTime;
13  import static org.kuali.common.util.log.Loggers.newLogger;
14  
15  import java.nio.file.Path;
16  import java.util.List;
17  import java.util.Set;
18  
19  import org.kuali.common.aws.s3.S3Service;
20  import org.kuali.common.aws.s3.model.ListObjectsRequest;
21  import org.kuali.common.aws.s3.model.ObjectListing;
22  import org.kuali.common.aws.s3.model.ObjectSummary;
23  import org.kuali.common.core.build.ValidatingBuilder;
24  import org.slf4j.Logger;
25  
26  import com.google.common.base.Optional;
27  import com.google.common.base.Stopwatch;
28  import com.google.common.base.Supplier;
29  import com.google.common.collect.ImmutableSet;
30  
31  public class S3Scanner implements Supplier<Set<ObjectSummary>> {
32  
33  	private static final Logger logger = newLogger();
34  
35  	private final S3Service s3;
36  	private final String bucket;
37  	private final String hostname;
38  	private final Path basedir;
39  
40  	@Override
41  	public Set<ObjectSummary> get() {
42  		Stopwatch sw = createStarted();
43  		logger.info(format("scanning   -> s3://%s/%s%s", bucket, hostnameToKey().apply(hostname), basedir));
44  		String prefix = getBucketScanPrefix();
45  		List<ObjectSummary> right = scanRight(prefix);
46  		List<ObjectSummary> left = scanLeft();
47  		Set<ObjectSummary> set = ImmutableSet.copyOf(concat(right, left));
48  		logger.info(format("disk usage -> %s", sumFileObjects(set)));
49  		logger.info(format("elapsed    -> %s", getTime(sw)));
50  		return set;
51  	}
52  
53  	private List<ObjectSummary> scanRight(String prefix) {
54  		return s3.getCompleteList(bucket, prefix);
55  	}
56  
57  	private List<ObjectSummary> scanLeft() {
58  		String prefix = getBucketScanPrefix();
59  		List<String> dirs = allParentsAsListSingle().apply(prefix);
60  		List<ObjectSummary> list = newArrayList();
61  		for (String dir : dirs) {
62  			String s3Key = removeStart(dir, "/") + "/";
63  			Optional<ObjectSummary> summary = getObjectSummary(s3Key);
64  			if (summary.isPresent()) {
65  				list.add(summary.get());
66  			}
67  		}
68  		return list;
69  	}
70  
71  	private Optional<ObjectSummary> getObjectSummary(String key) {
72  		ListObjectsRequest request = ListObjectsRequest.builder(bucket).withMax(1).withPrefix(key).build();
73  		ObjectListing ol = s3.getObjectListing(request);
74  		List<ObjectSummary> list = ol.getSummaries();
75  		if (list.isEmpty()) {
76  			return absent();
77  		}
78  		ObjectSummary summary = list.iterator().next();
79  		if (summary.getKey().equals(key)) {
80  			return Optional.of(summary);
81  		} else {
82  			return absent();
83  		}
84  	}
85  
86  	private String getBucketScanPrefix() {
87  		return getHostnamePrefix() + basedir.toString();
88  	}
89  
90  	private String getHostnamePrefix() {
91  		return hostnameToKey().apply(hostname);
92  	}
93  
94  	private S3Scanner(Builder builder) {
95  		this.s3 = builder.s3;
96  		this.bucket = builder.bucket;
97  		this.hostname = builder.hostname;
98  		this.basedir = builder.basedir;
99  	}
100 
101 	public static Builder builder() {
102 		return new Builder();
103 	}
104 
105 	public static class Builder extends ValidatingBuilder<S3Scanner> {
106 
107 		private S3Service s3;
108 		private String bucket;
109 		private String hostname;
110 		private Path basedir;
111 
112 		public Builder withS3(S3Service s3) {
113 			this.s3 = s3;
114 			return this;
115 		}
116 
117 		public Builder withBucket(String bucket) {
118 			this.bucket = bucket;
119 			return this;
120 		}
121 
122 		public Builder withHostname(String hostname) {
123 			this.hostname = hostname;
124 			return this;
125 		}
126 
127 		public Builder withBasedir(Path basedir) {
128 			this.basedir = basedir;
129 			return this;
130 		}
131 
132 		@Override
133 		public S3Scanner build() {
134 			return validate(new S3Scanner(this));
135 		}
136 	}
137 
138 	public S3Service getS3() {
139 		return s3;
140 	}
141 
142 	public String getBucket() {
143 		return bucket;
144 	}
145 
146 	public String getHostname() {
147 		return hostname;
148 	}
149 
150 	public Path getBasedir() {
151 		return basedir;
152 	}
153 
154 }