Skip to content

Commit f903d21

Browse files
committed
Experiment with the Azure SDK
This may replace the jclouds azureblob provider. The implementation is incomplete, lacking some error codes and options. References #606.
1 parent 15fe7f3 commit f903d21

8 files changed

+726
-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)