diff --git a/src/main/java/org/gaul/s3proxy/Main.java b/src/main/java/org/gaul/s3proxy/Main.java index 7f08430..635f80e 100644 --- a/src/main/java/org/gaul/s3proxy/Main.java +++ b/src/main/java/org/gaul/s3proxy/Main.java @@ -23,10 +23,15 @@ import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystems; +import java.nio.file.PathMatcher; import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; @@ -103,6 +108,11 @@ public final class Main { 1, 20, 60 * 1000, factory); ImmutableMap.Builder> locators = ImmutableMap.builder(); + ImmutableMap.Builder>> globLocators = ImmutableMap.builder(); + Map>> + globBuilders = new HashMap<>(); + Set parsedIdentities = new HashSet<>(); for (File propertiesFile : options.propertiesFiles) { Properties properties = new Properties(); try (InputStream is = new FileInputStream(propertiesFile)) { @@ -117,14 +127,35 @@ public final class Main { String s3ProxyAuthorizationString = properties.getProperty( S3ProxyConstants.PROPERTY_AUTHORIZATION); + ImmutableList.Builder locatorBuckets = + new ImmutableList.Builder<>(); + + String localIdentity = ""; if (AuthenticationType.fromString(s3ProxyAuthorizationString) != AuthenticationType.NONE) { - String localIdentity = properties.getProperty( + localIdentity = properties.getProperty( S3ProxyConstants.PROPERTY_IDENTITY); String localCredential = properties.getProperty( S3ProxyConstants.PROPERTY_CREDENTIAL); - locators.put(localIdentity, Maps.immutableEntry( - localCredential, blobStore)); + if (parsedIdentities.add(localIdentity)) { + locators.put(localIdentity, + Maps.immutableEntry(localCredential, blobStore)); + } + } + ImmutableList.Builder> + globBuilder = globBuilders.get(localIdentity); + if (globBuilder == null) { + globBuilder = new ImmutableList.Builder<>(); + globBuilders.put(localIdentity, globBuilder); + } + for (String key : properties.stringPropertyNames()) { + if (key.startsWith(S3ProxyConstants.PROPERTY_BUCKET_LOCATOR)) { + locatorBuckets.add(properties.getProperty(key)); + globBuilder.add(Maps.immutableEntry( + FileSystems.getDefault().getPathMatcher( + "glob:" + properties.getProperty(key)), + blobStore)); + } } S3Proxy.Builder s3ProxyBuilder2 = S3Proxy.Builder @@ -149,21 +180,51 @@ public final class Main { throw e; } + for (Map.Entry>> entry : globBuilders.entrySet()) { + globLocators.put(entry.getKey(), entry.getValue().build()); + } + final Map> locator = locators.build(); + final Map>> + globLocator = globLocators.build(); if (!locator.isEmpty()) { s3Proxy.setBlobStoreLocator(new BlobStoreLocator() { @Override public Map.Entry locateBlobStore( String identity, String container, String blob) { - if (identity == null) { - if (locator.size() == 1) { - return locator.entrySet().iterator().next() - .getValue(); + Map.Entry locatorEntry = + locator.get(identity); + List> globEntries = + globLocator.get(identity); + if (globEntries != null) { + for (Map.Entry entry : + globLocator.get(identity)) { + if (entry.getKey().matches(FileSystems.getDefault() + .getPath(container))) { + return Maps.immutableEntry( + locatorEntry.getKey(), + entry.getValue()); + } } - throw new IllegalArgumentException( - "cannot use anonymous access with multiple" + - " backends"); + } + // Check if the anonymous access globs were configured + globEntries = globLocator.get(""); + if (globEntries != null) { + for (Map.Entry entry : + globEntries) { + if (entry.getKey().matches(FileSystems.getDefault() + .getPath(container))) { + return Maps.immutableEntry( + locatorEntry.getKey(), + entry.getValue()); + } + } + } + if (identity == null) { + return locator.entrySet().iterator().next().getValue(); } return locator.get(identity); } diff --git a/src/main/java/org/gaul/s3proxy/S3ProxyConstants.java b/src/main/java/org/gaul/s3proxy/S3ProxyConstants.java index 510a515..eec35bd 100644 --- a/src/main/java/org/gaul/s3proxy/S3ProxyConstants.java +++ b/src/main/java/org/gaul/s3proxy/S3ProxyConstants.java @@ -66,6 +66,18 @@ public final class S3ProxyConstants { "s3proxy.max-single-part-object-size"; public static final String PROPERTY_V4_MAX_NON_CHUNKED_REQUEST_SIZE = "s3proxy.v4-max-non-chunked-request-size"; + /** Used to locate blobstores by specified bucket names. Each property + * file should contain a list of buckets associated with it, e.g. + * s3proxy.bucket-locator.1 = data + * s3proxy.bucket-locator.2 = metadata + * s3proxy.bucket-locator.3 = other + * When a request is made for the specified bucket, the backend defined + * in that properties file is used. This allows using the same + * credentials in multiple properties file and select the backend based + * on the bucket names. + */ + public static final String PROPERTY_BUCKET_LOCATOR = + "s3proxy.bucket-locator"; /** When true, model eventual consistency using two storage backends. */ public static final String PROPERTY_EVENTUAL_CONSISTENCY = "s3proxy.eventual-consistency";