Skip to content

Commit 1037bf5

Browse files
committed
Add azureblob-sdk provider backed by Azure SDK
This may replace the jclouds azureblob provider. The implementation lacks some error codes and options. Fixes #606.
1 parent 017050d commit 1037bf5

8 files changed

+750
-1
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ Maven Central hosts S3Proxy artifacts and the wiki has
7474
* atmos
7575
* aws-s3 (Amazon-only)
7676
* azureblob
77+
* azureblob-sdk (newer but incomplete)
7778
* b2
7879
* filesystem (on-disk storage)
7980
* google-cloud-storage

pom.xml

+20
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,26 @@
401401
<artifactId>logback-classic</artifactId>
402402
<version>1.5.8</version>
403403
</dependency>
404+
<dependency>
405+
<groupId>com.azure</groupId>
406+
<artifactId>azure-storage-blob</artifactId>
407+
<version>12.28.0</version>
408+
</dependency>
409+
<dependency>
410+
<groupId>com.azure</groupId>
411+
<artifactId>azure-identity</artifactId>
412+
<version>1.13.3</version>
413+
</dependency>
414+
<dependency>
415+
<groupId>com.google.auto.service</groupId>
416+
<artifactId>auto-service</artifactId>
417+
<version>1.0-rc3</version>
418+
</dependency>
419+
<dependency>
420+
<groupId>com.google.guava</groupId>
421+
<artifactId>guava</artifactId>
422+
<version>32.0.0-jre</version>
423+
</dependency>
404424
<dependency>
405425
<groupId>javax.xml.bind</groupId>
406426
<artifactId>jaxb-api</artifactId>

src/main/java/org/gaul/s3proxy/S3ErrorCode.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
* List of S3 error codes. Reference:
2727
* http://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html
2828
*/
29-
enum S3ErrorCode {
29+
public enum S3ErrorCode {
3030
ACCESS_DENIED(HttpServletResponse.SC_FORBIDDEN, "Forbidden"),
3131
BAD_DIGEST(HttpServletResponse.SC_BAD_REQUEST, "Bad Request"),
3232
BUCKET_ALREADY_EXISTS(HttpServletResponse.SC_FORBIDDEN,
@@ -44,6 +44,8 @@ enum S3ErrorCode {
4444
"Your proposed upload is smaller than the minimum allowed object" +
4545
" size. Each part must be at least 5 MB in size, except the last" +
4646
" part."),
47+
INTERNAL_ERROR(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
48+
"An internal error occurred. Try again."),
4749
INVALID_ACCESS_KEY_ID(HttpServletResponse.SC_FORBIDDEN, "Forbidden"),
4850
INVALID_ARGUMENT(HttpServletResponse.SC_BAD_REQUEST, "Bad Request"),
4951
INVALID_BUCKET_NAME(HttpServletResponse.SC_BAD_REQUEST,

src/main/java/org/gaul/s3proxy/S3ProxyHandlerJetty.java

+8
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
import javax.annotation.Nullable;
2424

25+
import com.azure.storage.blob.models.BlobStorageException;
2526
import com.google.common.collect.ImmutableMap;
2627
import com.google.common.net.HttpHeaders;
2728

@@ -30,6 +31,7 @@
3031

3132
import org.eclipse.jetty.server.Request;
3233
import org.eclipse.jetty.server.handler.AbstractHandler;
34+
import org.gaul.s3proxy.azureblob.AzureBlobStore;
3335
import org.jclouds.blobstore.BlobStore;
3436
import org.jclouds.blobstore.ContainerNotFoundException;
3537
import org.jclouds.blobstore.KeyNotFoundException;
@@ -79,6 +81,12 @@ public void handle(String target, Request baseRequest,
7981

8082
handler.doHandle(baseRequest, request, response, is);
8183
baseRequest.setHandled(true);
84+
} catch (BlobStorageException bse) {
85+
S3ErrorCode code = AzureBlobStore.toS3ErrorCode(bse.getErrorCode());
86+
handler.sendSimpleErrorResponse(request, response, code,
87+
code.getMessage(), ImmutableMap.<String, String>of());
88+
baseRequest.setHandled(true);
89+
return;
8290
} catch (ContainerNotFoundException cnfe) {
8391
S3ErrorCode code = S3ErrorCode.NO_SUCH_BUCKET;
8492
handler.sendSimpleErrorResponse(request, response, code,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright 2014-2021 Andrew Gaul <andrew@gaul.org>
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.gaul.s3proxy.azureblob;
18+
19+
import java.net.URI;
20+
import java.util.Properties;
21+
22+
import com.google.common.collect.ImmutableSet;
23+
import com.google.inject.Module;
24+
25+
import org.jclouds.azure.storage.config.AuthType;
26+
import org.jclouds.azure.storage.config.AzureStorageProperties;
27+
import org.jclouds.blobstore.BlobStoreContext;
28+
import org.jclouds.blobstore.reference.BlobStoreConstants;
29+
import org.jclouds.reflect.Reflection2;
30+
import org.jclouds.rest.internal.BaseHttpApiMetadata;
31+
32+
33+
public final class AzureBlobApiMetadata extends BaseHttpApiMetadata {
34+
public AzureBlobApiMetadata() {
35+
this(builder());
36+
}
37+
38+
protected AzureBlobApiMetadata(Builder builder) {
39+
super(builder);
40+
}
41+
42+
private static Builder builder() {
43+
return new Builder();
44+
}
45+
46+
@Override
47+
public Builder toBuilder() {
48+
return builder().fromApiMetadata(this);
49+
}
50+
51+
public static Properties defaultProperties() {
52+
Properties properties = BaseHttpApiMetadata.defaultProperties();
53+
properties.setProperty(BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX,
54+
"x-ms-meta-");
55+
properties.setProperty(AzureStorageProperties.AUTH_TYPE,
56+
AuthType.AZURE_KEY.toString());
57+
properties.setProperty(AzureStorageProperties.ACCOUNT, "");
58+
properties.setProperty(AzureStorageProperties.TENANT_ID, "");
59+
return properties;
60+
}
61+
62+
// Fake API client
63+
private interface AzureBlobClient {
64+
}
65+
66+
public static final class Builder
67+
extends BaseHttpApiMetadata.Builder<AzureBlobClient, Builder> {
68+
protected Builder() {
69+
super(AzureBlobClient.class);
70+
id("azureblob-sdk")
71+
.name("Microsoft Azure Blob Service API")
72+
.identityName("Account Name")
73+
.credentialName("Access Key")
74+
// TODO: update
75+
.version("2017-11-09")
76+
.defaultEndpoint(
77+
"https://${jclouds.identity}.blob.core.windows.net")
78+
.documentation(URI.create(
79+
"https://learn.microsoft.com/en-us/rest/api/" +
80+
"storageservices/Blob-Service-REST-API"))
81+
.defaultProperties(AzureBlobApiMetadata.defaultProperties())
82+
.view(Reflection2.typeToken(BlobStoreContext.class))
83+
.defaultModules(ImmutableSet.<Class<? extends Module>>of(
84+
AzureBlobStoreContextModule.class));
85+
}
86+
87+
@Override
88+
public AzureBlobApiMetadata build() {
89+
return new AzureBlobApiMetadata(this);
90+
}
91+
92+
@Override
93+
protected Builder self() {
94+
return this;
95+
}
96+
}
97+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* Copyright 2014-2021 Andrew Gaul <andrew@gaul.org>
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.gaul.s3proxy.azureblob;
18+
19+
import java.net.URI;
20+
import java.util.Properties;
21+
22+
import com.google.auto.service.AutoService;
23+
24+
import org.jclouds.azure.storage.config.AzureStorageProperties;
25+
import org.jclouds.oauth.v2.config.CredentialType;
26+
import org.jclouds.oauth.v2.config.OAuthProperties;
27+
import org.jclouds.providers.ProviderMetadata;
28+
import org.jclouds.providers.internal.BaseProviderMetadata;
29+
30+
/**
31+
* Implementation of org.jclouds.types.ProviderMetadata for Microsoft Azure
32+
* Blob Service.
33+
*/
34+
@AutoService(ProviderMetadata.class)
35+
public final class AzureBlobProviderMetadata extends BaseProviderMetadata {
36+
public AzureBlobProviderMetadata() {
37+
super(builder());
38+
}
39+
40+
public AzureBlobProviderMetadata(Builder builder) {
41+
super(builder);
42+
}
43+
44+
public static Builder builder() {
45+
return new Builder();
46+
}
47+
48+
@Override
49+
public Builder toBuilder() {
50+
return builder().fromProviderMetadata(this);
51+
}
52+
53+
public static Properties defaultProperties() {
54+
Properties properties = new Properties();
55+
properties.put("oauth.endpoint", "https://#.microsoft.com/${" +
56+
AzureStorageProperties.TENANT_ID + "}/oauth2/token");
57+
properties.put(OAuthProperties.RESOURCE, "https://storage.azure.com");
58+
properties.put(OAuthProperties.CREDENTIAL_TYPE,
59+
CredentialType.CLIENT_CREDENTIALS_SECRET.toString());
60+
properties.put(AzureStorageProperties.ACCOUNT, "${jclouds.identity}");
61+
return properties;
62+
}
63+
public static final class Builder extends BaseProviderMetadata.Builder {
64+
protected Builder() {
65+
id("azureblob-sdk")
66+
.name("Microsoft Azure Blob Service")
67+
.apiMetadata(new AzureBlobApiMetadata())
68+
.endpoint("https://${" + AzureStorageProperties.ACCOUNT +
69+
"}.blob.core.windows.net")
70+
.homepage(URI.create(
71+
"http://www.microsoft.com/windowsazure/storage/"))
72+
.console(URI.create("https://windows.azure.com/default.aspx"))
73+
.linkedServices("azureblob", "azurequeue", "azuretable")
74+
.iso3166Codes("US-TX", "US-IL", "IE-D", "SG", "NL-NH", "HK")
75+
.defaultProperties(
76+
AzureBlobProviderMetadata.defaultProperties());
77+
}
78+
79+
@Override
80+
public AzureBlobProviderMetadata build() {
81+
return new AzureBlobProviderMetadata(this);
82+
}
83+
84+
@Override
85+
public Builder fromProviderMetadata(
86+
ProviderMetadata in) {
87+
super.fromProviderMetadata(in);
88+
return this;
89+
}
90+
}
91+
}

0 commit comments

Comments
 (0)