diff --git a/azure/pom.xml b/azure/pom.xml index 08fb285..4d38434 100644 --- a/azure/pom.xml +++ b/azure/pom.xml @@ -33,8 +33,12 @@ jgroups - com.microsoft.azure - azure-storage + com.azure + azure-identity + + + com.azure + azure-storage-blob com.fasterxml.jackson.core diff --git a/azure/src/main/java/org/jgroups/protocols/azure/AZURE_PING.java b/azure/src/main/java/org/jgroups/protocols/azure/AZURE_PING.java index aea8079..8fc5b59 100644 --- a/azure/src/main/java/org/jgroups/protocols/azure/AZURE_PING.java +++ b/azure/src/main/java/org/jgroups/protocols/azure/AZURE_PING.java @@ -18,16 +18,15 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.time.Duration; import java.util.List; -import com.microsoft.azure.storage.CloudStorageAccount; -import com.microsoft.azure.storage.StorageCredentials; -import com.microsoft.azure.storage.StorageCredentialsAccountAndKey; -import com.microsoft.azure.storage.blob.CloudBlob; -import com.microsoft.azure.storage.blob.CloudBlobClient; -import com.microsoft.azure.storage.blob.CloudBlobContainer; -import com.microsoft.azure.storage.blob.CloudBlockBlob; -import com.microsoft.azure.storage.blob.ListBlobItem; +import com.azure.identity.DefaultAzureCredentialBuilder; + +import com.azure.storage.blob.*; +import com.azure.storage.blob.models.BlobItem; +import com.azure.storage.blob.models.ListBlobsOptions; +import com.azure.storage.common.StorageSharedKeyCredential; import org.jgroups.Address; import org.jgroups.annotations.Property; import org.jgroups.conf.ClassConfigurator; @@ -49,7 +48,7 @@ public class AZURE_PING extends FILE_PING { @Property(description = "The name of the storage account.") protected String storage_account_name; - @Property(description = "The secret account access key.", exposeAsManagedAttribute = false) + @Property(description = "The secret account access key, can be left blank to try to obtain credentials from the environment.", exposeAsManagedAttribute = false) protected String storage_access_key; @Property(description = "Container to store ping information in. Must be valid DNS name.") @@ -63,7 +62,9 @@ public class AZURE_PING extends FILE_PING { public static final int STREAM_BUFFER_SIZE = 4096; - private CloudBlobContainer containerReference; + private BlobContainerClient containerClient; + + private static final Duration TIMEOUT = Duration.ofSeconds(1); static { ClassConfigurator.addProtocol((short) 530, AZURE_PING.class); @@ -77,18 +78,25 @@ public void init() throws Exception { // Can throw IAEs this.validateConfiguration(); + final BlobServiceClientBuilder blobClientBuilder = new BlobServiceClientBuilder(); + if (storage_access_key != null) { + blobClientBuilder.credential(new StorageSharedKeyCredential(storage_account_name, storage_access_key)); + } else { + blobClientBuilder.credential(new DefaultAzureCredentialBuilder().build()); + } + + blobClientBuilder.endpoint(new BlobUrlParts() + .setAccountName(storage_account_name) + .setScheme(use_https ? "https" : "http") + .setHost(endpoint_suffix) // endpoint suffix = host base component + .toUrl().toString()); + + try { - StorageCredentials credentials = new StorageCredentialsAccountAndKey(storage_account_name, storage_access_key); - CloudStorageAccount storageAccount; - if (endpoint_suffix != null) { - storageAccount = new CloudStorageAccount(credentials, use_https, endpoint_suffix); - } else { - storageAccount = new CloudStorageAccount(credentials, use_https); - } - CloudBlobClient blobClient = storageAccount.createCloudBlobClient(); - containerReference = blobClient.getContainerReference(container); - boolean created = containerReference.createIfNotExists(); + BlobServiceClient blobClient = blobClientBuilder.buildClient(); + containerClient = blobClient.getBlobContainerClient(container); + boolean created = containerClient.createIfNotExists(); if (created) { log.info("Created container named '%s'.", container); } else { @@ -107,11 +115,11 @@ public void validateConfiguration() throws IllegalArgumentException { || container.startsWith("-") || container.length() < 3 || container.length() > 63) { throw new IllegalArgumentException("Container name must be configured and must meet Azure requirements (must be a valid DNS name)."); } - // Account name and access key must be both configured for write access - if (storage_account_name == null || storage_access_key == null) { - throw new IllegalArgumentException("Account name and key must be configured."); + // Account name and must be configured + if (storage_account_name == null) { + throw new IllegalArgumentException("Account name must be configured."); } - // Lets inform users here that https would be preferred + // Let's inform users here that https would be preferred if (!use_https) { log.info("Configuration is using HTTP, consider switching to HTTPS instead."); } @@ -132,15 +140,14 @@ protected void readAll(final List
members, final String clustername, fi String prefix = sanitize(clustername); - Iterable listBlobItems = containerReference.listBlobs(prefix); - for (ListBlobItem blobItem : listBlobItems) { + Iterable blobItems = containerClient.listBlobs(new ListBlobsOptions().setPrefix(prefix), TIMEOUT); + for (BlobItem blobItem : blobItems) { try { // If the item is a blob and not a virtual directory. - // n.b. what an ugly API this is - if (blobItem instanceof CloudBlob) { - CloudBlob blob = (CloudBlob) blobItem; + if (!blobItem.isPrefix()) { + BlobClient blobClient = containerClient.getBlobClient(blobItem.getName()); ByteArrayOutputStream os = new ByteArrayOutputStream(STREAM_BUFFER_SIZE); - blob.download(os); + blobClient.downloadStream(os); byte[] pingBytes = os.toByteArray(); parsePingData(pingBytes, members, responses); } @@ -189,8 +196,8 @@ protected void write(final List list, final String clustername) { byte[] data = out.toByteArray(); // Upload the file - CloudBlockBlob blob = containerReference.getBlockBlobReference(filename); - blob.upload(new ByteArrayInputStream(data), data.length); + BlobClient blobClient = containerClient.getBlobClient(filename); + blobClient.upload(new ByteArrayInputStream(data), data.length); } catch (Exception ex) { log.error("Error marshalling and uploading ping data.", ex); @@ -207,8 +214,8 @@ protected void remove(final String clustername, final Address addr) { String filename = addressToFilename(clustername, addr); try { - CloudBlockBlob blob = containerReference.getBlockBlobReference(filename); - boolean deleted = blob.deleteIfExists(); + BlobClient blobClient = containerClient.getBlobClient(filename); + boolean deleted = blobClient.deleteIfExists(); if (deleted) { log.debug("Tried to delete file '%s' but it was already deleted.", filename); @@ -229,17 +236,18 @@ protected void removeAll(String clustername) { clustername = sanitize(clustername); - Iterable listBlobItems = containerReference.listBlobs(clustername); - for (ListBlobItem blobItem : listBlobItems) { + Iterable blobItems = containerClient.listBlobs( + new ListBlobsOptions().setPrefix(clustername), TIMEOUT); + for (BlobItem blobItem : blobItems) { try { // If the item is a blob and not a virtual directory. - if (blobItem instanceof CloudBlob) { - CloudBlob blob = (CloudBlob) blobItem; - boolean deleted = blob.deleteIfExists(); + if (!blobItem.isPrefix()) { + BlobClient blobClient = containerClient.getBlobClient(blobItem.getName()); + boolean deleted = blobClient.deleteIfExists(); if (deleted) { - log.trace("Deleted file '%s'.", blob.getName()); + log.trace("Deleted file '%s'.", blobItem.getName()); } else { - log.debug("Tried to delete file '%s' but it was already deleted.", blob.getName()); + log.debug("Tried to delete file '%s' but it was already deleted.", blobItem.getName()); } } } catch (Exception e) { diff --git a/azure/src/test/java/org/jgroups/protocols/azure/AZURE_PINGDiscoveryTest.java b/azure/src/test/java/org/jgroups/protocols/azure/AZURE_PINGDiscoveryTest.java index 87a9fa2..cacdb0a 100644 --- a/azure/src/test/java/org/jgroups/protocols/azure/AZURE_PINGDiscoveryTest.java +++ b/azure/src/test/java/org/jgroups/protocols/azure/AZURE_PINGDiscoveryTest.java @@ -50,18 +50,15 @@ public class AZURE_PINGDiscoveryTest { public void testProtocolStack() throws Exception { JChannel channel = new JChannel(STACK_XML_CONFIGURATION); - channel.getProtocolStack().getProtocols().replaceAll(protocol -> { - if (protocol instanceof AZURE_PING) { - return new AZURE_PING(); - } else { - return protocol; - } - }); - - try { + try (channel) { + channel.getProtocolStack().getProtocols().replaceAll(protocol -> { + if (protocol instanceof AZURE_PING) { + return new AZURE_PING(); + } else { + return protocol; + } + }); channel.connect(RANDOM_CLUSTER_NAME); - } finally { - channel.close(); } } diff --git a/pom.xml b/pom.xml index 22c4a1e..6bacf0d 100644 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,7 @@ 5.3.6.Final - 8.6.6 + 1.2.23 2.17.1 @@ -81,18 +81,17 @@ jgroups ${version.org.jgroups} + + - com.microsoft.azure - azure-storage - ${version.com.microsoft.azure.azure-storage} - - - * - * - - + com.azure + azure-sdk-bom + ${version.com.azure-azure-sdk-bom} + pom + import + com.fasterxml.jackson.core