You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by mi...@apache.org on 2022/02/08 16:11:09 UTC
[jackrabbit-oak] branch trunk updated: OAK-9680 Add support for Azure SAS URIs to oak-segment-azure
This is an automated email from the ASF dual-hosted git repository.
miroslav pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
The following commit(s) were added to refs/heads/trunk by this push:
new 82a33f5 OAK-9680 Add support for Azure SAS URIs to oak-segment-azure
new fd32acb Merge pull request #479 from jelmini/feature/sas_uri_support
82a33f5 is described below
commit 82a33f5187ca4149849dc0e92475dccb89082684
Author: Carlo Jelmini <je...@adobe.com>
AuthorDate: Mon Jan 31 19:56:46 2022 +0100
OAK-9680 Add support for Azure SAS URIs to oak-segment-azure
Allow using Shared Access Signature URI to connect to Azure Storage.
---
oak-segment-azure/pom.xml | 6 +
.../segment/azure/AzureSegmentStoreService.java | 90 +++++--
.../oak/segment/azure/Configuration.java | 13 +-
.../azure/AzureSegmentStoreServiceTest.java | 262 +++++++++++++++++++++
.../oak/segment/azure/AzuriteDockerRule.java | 55 +++--
5 files changed, 380 insertions(+), 46 deletions(-)
diff --git a/oak-segment-azure/pom.xml b/oak-segment-azure/pom.xml
index 95b95cf..04cf956 100644
--- a/oak-segment-azure/pom.xml
+++ b/oak-segment-azure/pom.xml
@@ -213,6 +213,12 @@
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
+ <scope>test</scope>
+ </dependency>
+
</dependencies>
</project>
diff --git a/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/AzureSegmentStoreService.java b/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/AzureSegmentStoreService.java
index 11a9b75..489c4d1 100644
--- a/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/AzureSegmentStoreService.java
+++ b/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/AzureSegmentStoreService.java
@@ -21,7 +21,9 @@ package org.apache.jackrabbit.oak.segment.azure;
import com.microsoft.azure.storage.CloudStorageAccount;
import com.microsoft.azure.storage.StorageException;
import com.microsoft.azure.storage.blob.CloudBlobContainer;
+import org.apache.commons.lang3.StringUtils;
import org.apache.jackrabbit.oak.segment.spi.persistence.SegmentNodeStorePersistence;
+import org.jetbrains.annotations.NotNull;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
@@ -37,8 +39,8 @@ import java.security.InvalidKeyException;
import java.util.Properties;
@Component(
- configurationPolicy = ConfigurationPolicy.REQUIRE,
- configurationPid = {Configuration.PID})
+ configurationPolicy = ConfigurationPolicy.REQUIRE,
+ configurationPid = {Configuration.PID})
public class AzureSegmentStoreService {
private static final Logger log = LoggerFactory.getLogger(AzureSegmentStoreService.class);
@@ -49,12 +51,11 @@ public class AzureSegmentStoreService {
private ServiceRegistration registration;
- private SegmentNodeStorePersistence persistence;
-
@Activate
public void activate(ComponentContext context, Configuration config) throws IOException {
- persistence = createAzurePersistence(config);
- registration = context.getBundleContext().registerService(SegmentNodeStorePersistence.class.getName(), persistence, new Properties());
+ AzurePersistence persistence = createAzurePersistenceFrom(config);
+ registration = context.getBundleContext()
+ .registerService(SegmentNodeStorePersistence.class.getName(), persistence, new Properties());
}
@Deactivate
@@ -63,35 +64,72 @@ public class AzureSegmentStoreService {
registration.unregister();
registration = null;
}
- persistence = null;
}
- private static SegmentNodeStorePersistence createAzurePersistence(Configuration configuration) throws IOException {
+ private static AzurePersistence createAzurePersistenceFrom(Configuration configuration) throws IOException {
+ if (!StringUtils.isBlank(configuration.connectionURL())) {
+ return createPersistenceFromConnectionURL(configuration);
+ }
+ if (!StringUtils.isBlank(configuration.sharedAccessSignature())) {
+ return createPersistenceFromSasUri(configuration);
+ }
+ return createPersistenceFromAccessKey(configuration);
+ }
+
+ private static AzurePersistence createPersistenceFromAccessKey(Configuration configuration) throws IOException {
+ StringBuilder connectionString = new StringBuilder();
+ connectionString.append("DefaultEndpointsProtocol=https;");
+ connectionString.append("AccountName=").append(configuration.accountName()).append(';');
+ connectionString.append("AccountKey=").append(configuration.accessKey()).append(';');
+ if (!StringUtils.isBlank(configuration.blobEndpoint())) {
+ connectionString.append("BlobEndpoint=").append(configuration.blobEndpoint()).append(';');
+ }
+ return createAzurePersistence(connectionString.toString(), configuration, true);
+ }
+
+ private static AzurePersistence createPersistenceFromSasUri(Configuration configuration) throws IOException {
+ StringBuilder connectionString = new StringBuilder();
+ connectionString.append("DefaultEndpointsProtocol=https;");
+ connectionString.append("AccountName=").append(configuration.accountName()).append(';');
+ connectionString.append("SharedAccessSignature=").append(configuration.sharedAccessSignature()).append(';');
+ if (!StringUtils.isBlank(configuration.blobEndpoint())) {
+ connectionString.append("BlobEndpoint=").append(configuration.blobEndpoint()).append(';');
+ }
+ return createAzurePersistence(connectionString.toString(), configuration, false);
+ }
+
+ @NotNull
+ private static AzurePersistence createPersistenceFromConnectionURL(Configuration configuration) throws IOException {
+ return createAzurePersistence(configuration.connectionURL(), configuration, true);
+ }
+
+ @NotNull
+ private static AzurePersistence createAzurePersistence(
+ String connectionString,
+ Configuration configuration,
+ boolean createContainer
+ ) throws IOException {
try {
- StringBuilder connectionString = new StringBuilder();
- if (configuration.connectionURL() == null || configuration.connectionURL().trim().isEmpty()) {
- connectionString.append("DefaultEndpointsProtocol=https;");
- connectionString.append("AccountName=").append(configuration.accountName()).append(';');
- connectionString.append("AccountKey=").append(configuration.accessKey()).append(';');
- } else {
- connectionString.append(configuration.connectionURL());
- }
- CloudStorageAccount cloud = CloudStorageAccount.parse(connectionString.toString());
- log.info("Connection string: '{}'", cloud.toString());
+ CloudStorageAccount cloud = CloudStorageAccount.parse(connectionString);
+ log.info("Connection string: '{}'", cloud);
CloudBlobContainer container = cloud.createCloudBlobClient().getContainerReference(configuration.containerName());
- container.createIfNotExists();
-
- String path = configuration.rootPath();
- if (path != null && path.length() > 0 && path.charAt(0) == '/') {
- path = path.substring(1);
+ if (createContainer) {
+ container.createIfNotExists();
}
-
- AzurePersistence persistence = new AzurePersistence(container.getDirectoryReference(path));
- return persistence;
+ String path = normalizePath(configuration.rootPath());
+ return new AzurePersistence(container.getDirectoryReference(path));
} catch (StorageException | URISyntaxException | InvalidKeyException e) {
throw new IOException(e);
}
}
+ @NotNull
+ private static String normalizePath(@NotNull String rootPath) {
+ if (rootPath.length() > 0 && rootPath.charAt(0) == '/') {
+ return rootPath.substring(1);
+ }
+ return rootPath;
+ }
+
}
diff --git a/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/Configuration.java b/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/Configuration.java
index 11da64d..e5cef06 100644
--- a/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/Configuration.java
+++ b/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/Configuration.java
@@ -54,6 +54,17 @@ import static org.apache.jackrabbit.oak.segment.azure.Configuration.PID;
@AttributeDefinition(
name = "Azure connection string (optional)",
description = "Connection string to be used to connect to the Azure Storage. " +
- "Setting it will override the accountName and accessKey properties.")
+ "Setting it will take precedence over accountName/accessKey and sharedAccessSignature properties.")
String connectionURL() default "";
+
+ @AttributeDefinition(
+ name = "Azure Shared Access Signature (optional)",
+ description = "Shared Access Signature string to be used to connect to the Azure Storage. " +
+ "Setting it will take precedence over accountName/accessKey properties.")
+ String sharedAccessSignature() default "";
+
+ @AttributeDefinition(
+ name = "Azure Blob Endpoint URL (optional)",
+ description = "Blob Endpoint URL used to connect to the Azure Storage")
+ String blobEndpoint() default "";
}
\ No newline at end of file
diff --git a/oak-segment-azure/src/test/java/org/apache/jackrabbit/oak/segment/azure/AzureSegmentStoreServiceTest.java b/oak-segment-azure/src/test/java/org/apache/jackrabbit/oak/segment/azure/AzureSegmentStoreServiceTest.java
new file mode 100644
index 0000000..f10ec24
--- /dev/null
+++ b/oak-segment-azure/src/test/java/org/apache/jackrabbit/oak/segment/azure/AzureSegmentStoreServiceTest.java
@@ -0,0 +1,262 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.segment.azure;
+
+import com.google.common.collect.ImmutableSet;
+import com.microsoft.azure.storage.StorageException;
+import com.microsoft.azure.storage.blob.*;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.net.URISyntaxException;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.*;
+import java.util.stream.StreamSupport;
+import org.apache.jackrabbit.oak.segment.spi.persistence.SegmentNodeStorePersistence;
+import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
+import org.jetbrains.annotations.NotNull;
+import org.junit.*;
+
+import static com.microsoft.azure.storage.blob.SharedAccessBlobPermissions.*;
+import static java.util.stream.Collectors.toSet;
+import static org.junit.Assert.*;
+
+public class AzureSegmentStoreServiceTest {
+
+ @ClassRule
+ public static AzuriteDockerRule azurite = new AzuriteDockerRule();
+
+ @Rule
+ public final OsgiContext context = new OsgiContext();
+
+ private static final EnumSet<SharedAccessBlobPermissions> READ_ONLY = EnumSet.of(READ, LIST);
+ private static final EnumSet<SharedAccessBlobPermissions> READ_WRITE = EnumSet.of(READ, LIST, CREATE, WRITE, ADD);
+ private static final ImmutableSet<String> BLOBS = ImmutableSet.of("blob1", "blob2");
+
+ private CloudBlobContainer container;
+
+ @Before
+ public void setup() throws Exception {
+ container = azurite.getContainer(AzureSegmentStoreService.DEFAULT_CONTAINER_NAME);
+ for (String blob : BLOBS) {
+ container.getBlockBlobReference(blob + ".txt").uploadText(blob);
+ }
+ }
+
+ @Test
+ public void connectWithSharedAccessSignatureURL_readOnly() throws Exception {
+ String sasToken = container.generateSharedAccessSignature(policy(READ_ONLY), null);
+
+ AzureSegmentStoreService azureSegmentStoreService = new AzureSegmentStoreService();
+ azureSegmentStoreService.activate(context.componentContext(), getConfigurationWithSharedAccessSignature(sasToken));
+
+ SegmentNodeStorePersistence persistence = context.getService(SegmentNodeStorePersistence.class);
+ assertNotNull(persistence);
+ assertWriteAccessNotGranted(persistence);
+ assertReadAccessGranted(persistence, BLOBS);
+ }
+
+ @Test
+ public void connectWithSharedAccessSignatureURL_readWrite() throws Exception {
+ String sasToken = container.generateSharedAccessSignature(policy(READ_WRITE), null);
+
+ AzureSegmentStoreService azureSegmentStoreService = new AzureSegmentStoreService();
+ azureSegmentStoreService.activate(context.componentContext(), getConfigurationWithSharedAccessSignature(sasToken));
+
+ SegmentNodeStorePersistence persistence = context.getService(SegmentNodeStorePersistence.class);
+ assertNotNull(persistence);
+ assertWriteAccessGranted(persistence);
+ assertReadAccessGranted(persistence, concat(BLOBS, "test"));
+ }
+
+ @Test
+ public void connectWithSharedAccessSignatureURL_expired() throws Exception {
+ SharedAccessBlobPolicy expiredPolicy = policy(READ_WRITE, yesterday());
+ String sasToken = container.generateSharedAccessSignature(expiredPolicy, null);
+
+ AzureSegmentStoreService azureSegmentStoreService = new AzureSegmentStoreService();
+ azureSegmentStoreService.activate(context.componentContext(), getConfigurationWithSharedAccessSignature(sasToken));
+
+ SegmentNodeStorePersistence persistence = context.getService(SegmentNodeStorePersistence.class);
+ assertNotNull(persistence);
+ assertWriteAccessNotGranted(persistence);
+ assertReadAccessNotGranted(persistence);
+ }
+
+ @Test
+ public void connectWithAccessKey() throws Exception {
+ AzureSegmentStoreService azureSegmentStoreService = new AzureSegmentStoreService();
+ azureSegmentStoreService.activate(context.componentContext(), getConfigurationWithAccessKey(AzuriteDockerRule.ACCOUNT_KEY));
+
+ SegmentNodeStorePersistence persistence = context.getService(SegmentNodeStorePersistence.class);
+ assertNotNull(persistence);
+ assertWriteAccessGranted(persistence);
+ assertReadAccessGranted(persistence, concat(BLOBS, "test"));
+ }
+
+ @Test
+ public void connectWithConnectionURL() throws Exception {
+ AzureSegmentStoreService azureSegmentStoreService = new AzureSegmentStoreService();
+ azureSegmentStoreService.activate(context.componentContext(), getConfigurationWithConfigurationURL(AzuriteDockerRule.ACCOUNT_KEY));
+
+ SegmentNodeStorePersistence persistence = context.getService(SegmentNodeStorePersistence.class);
+ assertNotNull(persistence);
+ assertWriteAccessGranted(persistence);
+ assertReadAccessGranted(persistence, concat(BLOBS, "test"));
+ }
+
+ @Test
+ public void deactivate() throws Exception {
+ AzureSegmentStoreService azureSegmentStoreService = new AzureSegmentStoreService();
+ azureSegmentStoreService.activate(context.componentContext(), getConfigurationWithAccessKey(AzuriteDockerRule.ACCOUNT_KEY));
+ assertNotNull(context.getService(SegmentNodeStorePersistence.class));
+
+ azureSegmentStoreService.deactivate();
+ assertNull(context.getService(SegmentNodeStorePersistence.class));
+ }
+
+ @NotNull
+ private static SharedAccessBlobPolicy policy(EnumSet<SharedAccessBlobPermissions> permissions, Instant expirationTime) {
+ SharedAccessBlobPolicy sharedAccessBlobPolicy = new SharedAccessBlobPolicy();
+ sharedAccessBlobPolicy.setPermissions(permissions);
+ sharedAccessBlobPolicy.setSharedAccessExpiryTime(Date.from(expirationTime));
+ return sharedAccessBlobPolicy;
+ }
+
+ @NotNull
+ private static SharedAccessBlobPolicy policy(EnumSet<SharedAccessBlobPermissions> permissions) {
+ return policy(permissions, Instant.now().plus(Duration.ofDays(7)));
+ }
+
+ private static void assertReadAccessGranted(SegmentNodeStorePersistence persistence, Set<String> expectedBlobs) throws Exception {
+ CloudBlobContainer container = getContainerFrom(persistence);
+ Set<String> actualBlobNames = StreamSupport.stream(container.listBlobs().spliterator(), false)
+ .map(blob -> blob.getUri().getPath())
+ .map(path -> path.substring(path.lastIndexOf('/') + 1))
+ .collect(toSet());
+ Set<String> expectedBlobNames = expectedBlobs.stream().map(name -> name + ".txt").collect(toSet());
+
+ assertEquals(expectedBlobNames, actualBlobNames);
+
+ Set<String> actualBlobContent = actualBlobNames.stream()
+ .map(name -> {
+ try {
+ return container.getBlockBlobReference(name).downloadText();
+ } catch (StorageException | IOException | URISyntaxException e) {
+ throw new RuntimeException("Error while reading blob " + name, e);
+ }
+ })
+ .collect(toSet());
+ assertEquals(expectedBlobs, actualBlobContent);
+ }
+
+ private static void assertWriteAccessGranted(SegmentNodeStorePersistence persistence) throws Exception {
+ getContainerFrom(persistence)
+ .getBlockBlobReference("test.txt").uploadText("test");
+ }
+
+ private static CloudBlobContainer getContainerFrom(SegmentNodeStorePersistence persistence) throws Exception {
+ return ((AzurePersistence) persistence).getSegmentstoreDirectory().getContainer();
+ }
+
+ private static void assertWriteAccessNotGranted(SegmentNodeStorePersistence persistence) {
+ try {
+ assertWriteAccessGranted(persistence);
+ fail("Write access should not be granted, but writing to the storage succeeded.");
+ } catch (Exception e) {
+ // successful
+ }
+ }
+
+ private static void assertReadAccessNotGranted(SegmentNodeStorePersistence persistence) {
+ try {
+ assertReadAccessGranted(persistence, BLOBS);
+ fail("Read access should not be granted, but reading from the storage succeeded.");
+ } catch (Exception e) {
+ // successful
+ }
+ }
+
+ private static Instant yesterday() {
+ return Instant.now().minus(Duration.ofDays(1));
+ }
+
+ private static ImmutableSet<String> concat(ImmutableSet<String> blobs, String element) {
+ return ImmutableSet.<String>builder().addAll(blobs).add(element).build();
+ }
+
+ private static Configuration getConfigurationWithSharedAccessSignature(String sasToken) {
+ return getConfiguration(sasToken, null, null);
+ }
+
+ private static Configuration getConfigurationWithAccessKey(String accessKey) {
+ return getConfiguration(null, accessKey, null);
+ }
+
+ private static Configuration getConfigurationWithConfigurationURL(String accessKey) {
+ String connectionString = "DefaultEndpointsProtocol=https;"
+ + "BlobEndpoint=" + azurite.getBlobEndpoint() + ';'
+ + "AccountName=" + AzuriteDockerRule.ACCOUNT_NAME + ';'
+ + "AccountKey=" + accessKey + ';';
+ return getConfiguration(null, null, connectionString);
+ }
+
+ @NotNull
+ private static Configuration getConfiguration(String sasToken, String accessKey, String connectionURL) {
+ return new Configuration() {
+ @Override
+ public String accountName() {
+ return AzuriteDockerRule.ACCOUNT_NAME;
+ }
+
+ @Override
+ public String containerName() {
+ return AzureSegmentStoreService.DEFAULT_CONTAINER_NAME;
+ }
+
+ @Override
+ public String accessKey() {
+ return accessKey != null ? accessKey : "";
+ }
+
+ @Override
+ public String rootPath() {
+ return AzureSegmentStoreService.DEFAULT_ROOT_PATH;
+ }
+
+ @Override
+ public String connectionURL() {
+ return connectionURL != null ? connectionURL : "";
+ }
+
+ @Override
+ public String sharedAccessSignature() {
+ return sasToken != null ? sasToken : "";
+ }
+
+ @Override
+ public String blobEndpoint() {
+ return azurite.getBlobEndpoint();
+ }
+
+ @Override
+ public Class<? extends Annotation> annotationType() {
+ return Configuration.class;
+ }
+ };
+ }
+}
diff --git a/oak-segment-azure/src/test/java/org/apache/jackrabbit/oak/segment/azure/AzuriteDockerRule.java b/oak-segment-azure/src/test/java/org/apache/jackrabbit/oak/segment/azure/AzuriteDockerRule.java
index 283d1cc..231a9ad 100644
--- a/oak-segment-azure/src/test/java/org/apache/jackrabbit/oak/segment/azure/AzuriteDockerRule.java
+++ b/oak-segment-azure/src/test/java/org/apache/jackrabbit/oak/segment/azure/AzuriteDockerRule.java
@@ -20,10 +20,12 @@ import com.arakelian.docker.junit.DockerRule;
import com.arakelian.docker.junit.model.ImmutableDockerConfig;
import com.microsoft.azure.storage.CloudStorageAccount;
import com.microsoft.azure.storage.StorageException;
+import com.microsoft.azure.storage.blob.CloudBlobClient;
import com.microsoft.azure.storage.blob.CloudBlobContainer;
import com.spotify.docker.client.DefaultDockerClient;
import com.spotify.docker.client.auth.FixedRegistryAuthSupplier;
+import org.jetbrains.annotations.NotNull;
import org.junit.Assume;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
@@ -34,42 +36,57 @@ import java.security.InvalidKeyException;
public class AzuriteDockerRule implements TestRule {
- private static final String IMAGE = "trekawek/azurite";
+ private static final String IMAGE = "mcr.microsoft.com/azure-storage/azurite:3.15.0";
+
+ public static final String ACCOUNT_KEY = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
+ public static final String ACCOUNT_NAME = "devstoreaccount1";
private final DockerRule wrappedRule;
public AzuriteDockerRule() {
wrappedRule = new DockerRule(ImmutableDockerConfig.builder()
- .image(IMAGE)
- .name("oak-test-azurite")
- .ports("10000")
- .addStartedListener(container -> {
- container.waitForPort("10000/tcp");
- container.waitForLog("Azure Blob Storage Emulator listening on port 10000");
- })
- .addContainerConfigurer(builder -> builder.env("executable=blob"))
- .alwaysRemoveContainer(true)
- .build());
-
+ .image(IMAGE)
+ .name("oak-test-azurite")
+ .ports("10000")
+ .addStartedListener(container -> {
+ container.waitForPort("10000/tcp");
+ container.waitForLog("Azurite Blob service is successfully listening at http://0.0.0.0:10000");
+ })
+ .addContainerConfigurer(builder -> builder.env("executable=blob"))
+ .alwaysRemoveContainer(true)
+ .build());
}
public CloudBlobContainer getContainer(String name) throws URISyntaxException, StorageException, InvalidKeyException {
- int mappedPort = getMappedPort();
- CloudStorageAccount cloud = CloudStorageAccount.parse("DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:" + mappedPort + "/devstoreaccount1;");
- CloudBlobContainer container = cloud.createCloudBlobClient().getContainerReference(name);
+ CloudStorageAccount cloud = getCloudStorageAccount();
+ CloudBlobClient cloudBlobClient = cloud.createCloudBlobClient();
+ CloudBlobContainer container = cloudBlobClient.getContainerReference(name);
container.deleteIfExists();
container.create();
return container;
}
+ public CloudStorageAccount getCloudStorageAccount() throws URISyntaxException, InvalidKeyException {
+ String blobEndpoint = "BlobEndpoint=" + getBlobEndpoint();
+ String accountName = "AccountName=" + ACCOUNT_NAME;
+ String accountKey = "AccountKey=" + ACCOUNT_KEY;
+ return CloudStorageAccount.parse("DefaultEndpointsProtocol=http;" + ";" + accountName + ";" + accountKey + ";" + blobEndpoint);
+ }
+
+ @NotNull
+ public String getBlobEndpoint() {
+ int mappedPort = getMappedPort();
+ return "http://127.0.0.1:" + mappedPort + "/devstoreaccount1";
+ }
+
@Override
public Statement apply(Statement statement, Description description) {
try {
DefaultDockerClient client = DefaultDockerClient.fromEnv()
- .connectTimeoutMillis(5000L)
- .readTimeoutMillis(20000L)
- .registryAuthSupplier(new FixedRegistryAuthSupplier())
- .build();
+ .connectTimeoutMillis(5000L)
+ .readTimeoutMillis(20000L)
+ .registryAuthSupplier(new FixedRegistryAuthSupplier())
+ .build();
client.ping();
client.pull(IMAGE);
client.close();