Host your maven artifacts using Azure Blob Storage

If you use Microsoft Azure and you use Java for your projects then Azure Blob Storage is a great place to host your teams artifcats.

It is easy to setup and pretty cheap. Also it is much simpler than setting one of the existing repository options (jfrog, nexus, archiva etc) if you are not particularly interested in their features.

To get started you need to specify a maven wagon which supports azure blob storage.
We will use the Azure storage wagon.

Let’s get started by creating a maven project

mvn archetype:generate -DgroupId=com.test.apps -DartifactId=AzureWagonTest -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

We are going to add a simple service.

package com.test.apps;

public class HelloService {

    public String sayHello() {

        return "Hello";
    }
}

Then we are going to add the maven wagon which will upload and fetch our binaries to azure blob storage.

    <build>
        <extensions>
            <extension>
                <groupId>com.gkatzioura.maven.cloud</groupId>
                <artifactId>azure-storage-wagon</artifactId>
                <version>1.0</version>
            </extension>
        </extensions>
    </build>

Then we shall create the azure storage account that will host our artifacts.

Then we shall create a new container called snapshot. This container will contain our snapshot repositories.

We can go through the same process in order to create a release repository.
Be aware that there is no need to to create different containers for each repository. You can have repositories under the same container.

Now that we have set up our storage account in azure we shall set the distribution management on our maven project.

    <distributionManagement>
        <snapshotRepository>
            <id>my-repo-bucket-snapshot</id>
            <url>bs://mavenrepository/snapshot</url>
        </snapshotRepository>
        <repository>
            <id>my-repo-bucket-release</id>
            <url>bs://mavenrepository/release</url>
        </repository>
    </distributionManagement>

From the maven documentation

Where as the repositories element specifies in the POM the location and manner in which Maven may download remote artifacts for use by the current project, distributionManagement specifies where (and how) this project will get to a remote repository when it is deployed. The repository elements will be used for snapshot distribution if the snapshotRepository is not defined.

The next step is the most crucial and this has to to do with authenticating to azure.

What you need is your storage account name and the key of the storage account.
In order to retrieve both you have to navigate to the Access keys of your Storage Account at the Settings section.

Then we shall specify our storage account credentials on the ~/.m2/settings.xml

  <servers>
    <server>
      <id>my-repo-bucket-snapshot</id>
      <username>mavenrepository</username>
      <password>eXampLEkeyEMI/K7EXAMP/bPxRfiCYEXAMPLEKEY</password>
    </server>
    <server>
      <id>my-repo-bucket-release</id>
      <username>mavenrepository</username>
      <password>eXampLEkeyEMI/K7EXAMP/bPxRfiCYEXAMPLEKEY</password>
    </server>
  </servers>

Be aware that you have to specify credentials for each repository specified.

And now the easiest part which is deploying.

mvn deploy

Now since your artifact has been deployed you can use it in another repo by specifying your repository and your wagon.

    <repositories>
        <repository>
            <id>my-repo-bucket-snapshot</id>
            <url>bs://mavenrepository/snapshot</url>
        </repository>
        <repository>
            <id>my-repo-bucket-release</id>
            <url>bs://mavenrepository/release</url>
        </repository>
    </repositories>

    <build>
        <extensions>
            <extension>
                <groupId>com.gkatzioura.maven.cloud</groupId>
                <artifactId>azure-storage-wagon</artifactId>
                <version>1.0</version>
            </extension>
        </extensions>
    </build>

That’s it! Next thing you know your artifact will be downloaded by maven through azure blob storage and used as a dependency in your new project.

30 thoughts on “Host your maven artifacts using Azure Blob Storage

  1. can this work with https instead of bs ? i tried and mvn reports
    ”’ReasonPhrase: Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature..”’

  2. thanks for the reply.

    i have the key in ~/.m2/settings.xml and your example works if i use this is the pom.xml:

    my-repo-bucket-release
    bs://mdlprodv2miscstorage/android-builds

    i get the auth error when i change the protocol, as below:

    my-repo-bucket-release
    https://mdlprodv2miscstorage.blob.core.windows.net/android-builds

    i’m curious about the ‘bs://’. can you give more detail about that and why changing it to https causes this?

    1. the comment system ate my xml code. to clarify, in the pom.xml, in the distributionManagement element i changed only the url elements’ protocol from bs to https.

  3. Even though i create a release container, by default it is pushing it to snapshot container on azure though i dont specify snapshot version inside pom. Can you please tell me ,how to push it to release container

    1. I’m having a similar issue. Have you resolved this issue since you’ve last posted this?

      Thanks,
      Patrick

  4. This appears to be working fine for me, but I’ve noticed that my artifacts that are being uploaded are having a timestamp appended. For example, mc3-couchdb-objects-1.2.1-20190306.165442-50.zip. I want just mc3-couchdb-objects-1.2.1.zip.

    Is this something within the connector, Maven or Azure Blobs?

    Thanks,
    Patrick

      1. Thanks for checking, but this is a non-issue. I’ve found that Maven 2 had an option to omit timestamps and then Maven 3 removed that feature.

        I was going down the wrong path anyway and this is not related to my problem, which ultimately is due to me being a dummy. đŸ™‚

        Thanks again,
        Patrick

  5. This has been a great thing that you made. Have you ever had issues where you’ve got two containers in one blob and you’re attempting to send snapshots to one and releases to the other, but everything just goes to snapshot?

    Let me show an example.

    In my pom.xml I have:
    within properties
    bs://snapshot.blob.core.windows.net/snapshot
    bs://snapshot.blob.core.windows.net/release

    then

    Release
    Release Repository
    ${release.url}

    Snapshot
    Snapshot Repository
    ${snapshot.url}

    then

    Release
    Release Repository

    true
    never
    warn

    false
    always
    warn

    ${release.url}
    default

    Snapshot
    Snapshot Repository

    false
    never
    fail

    true
    always
    fail

    ${snapshot.url}
    default

    Here are my settings.xml

    Release
    username
    password

    Snapshot
    username
    password

    In the Azure portal I’ve created a blob storage object and created two containers, snapshot and release. I’ve confirmed that the urls to hit them are the same as above from the properties.

    What’s annoying is that when I run my Maven build (via Jenkins) the job output will say that it’s uploading and downloading to both urls, but when I check on the Azure portal, only the snapshot container has data.

    I did setup and run with the snapshot folder first…maybe I need to clear cache somewhere? I’m doing mvn clean deploys.

    Apologies in advance, I’m new to Maven. đŸ˜¦

    Thanks for any feedback,
    Patrick

      1. It seems to be a maven thing.
        Maven shall deploy your artifacts to your release if you version does not contain the ‘-SNAPSHOT’ .
        If your version contains ‘-SNAPSHOT’ it gets deployed to the snapshot repo.

      2. That’s interesting. I’ll do more testing. I was ready to throw out my computer. đŸ™‚

        You’re the best,
        Patrick

      3. Do you suppose that it’s possible that Maven works differently with Nexus? The past URLs for Snapshots and Releases were different Nexus repo locations, and that appears to work correctly. Versions containing SNAPSHOT go to both snapshot and release endpoints when defined.

        Weird.

  6. No idea, but I am pretty sure it is not related to the wagon since the wagon has to follow certain guidelines.
    When it comes to nexus, the project binaries are hosted to nexus (maven central) and in order to deploy to snapshot or staging it is essential for the ‘-SNAPSHOT’ to be or not to be present in the version. So actually it always worked the same for me.

    1. Do you mean that you’ve always had SNAPSHOT and RELEASE in the respective versions and it goes to the correct places for you?

      Do you think that the trailing / could be causing issue?

      Here are what I have for snapshot and release. http address was the old place which worked, and the bs locations are going to the same blob, but different containers, but no matter how I name versions, Maven says it’s uploading/downloading to release URL, but it lies and is going to snapshot.

      snapshot:
      http://nexus-repo:8080/nexus/content/repositories/NexusSnapshot/
      bs://blob-stor.blob.core.windows.net/snapshot

      release:
      http://nexus-repo:8080/nexus/content/repositories/PBNexusRelease/
      bs://blob-store.blob.core.windows.net/release

      Sorry for the back and forth. I really appreciate your help and input.

      Thanks,
      Patrick

      1. – Do you mean that you’ve always had SNAPSHOT and RELEASE in the respective versions and it goes to the correct places for you?

        Yes

        – Do you think that the trailing / could be causing issue?

        What is the trailing?

        In order to go the release version should not contain SNAPSHOT, in order to go to SNAPSHOT version will contain SNAPSHOT.

  7. I was able to upload jars to blob using maven extensions which u mentions above.
    But i need to download using gradle , how can I use your extensions in gradle ??
    Can you please help.

  8. Hi,

    I tried to deploy the artifact programatically using MavenRepository.deployArtifact method. I had the configuration done as specified in the above post. I built the pomXML programatically and included the above related maven wagon. However during deployment I get the below error: Can anyone please help me resolve this

    Please note : I am new to using Maven. Please let me know, if you need further info

    Exception in thread “main” java.lang.RuntimeException: org.eclipse.aether.deployment.DeploymentException: Failed to deploy artifacts/metadata: Cannot access bs://mavenrepositorytest/snapshot with type default using the available connector factories: BasicRepositoryConnectorFactory
    at org.appformer.maven.integration.MavenRepository.deployArtifact(MavenRepository.java:281)
    at com.optum.sample.dynamic.drl.WaasRepository.deployArtifact(WaasRepository.java:49)
    at com.optum.sample.dynamic.drl.WaasRepository.deployArtifact(WaasRepository.java:41)
    at com.optum.sample.dynamic.drl.RulesGenerator.build(RulesGenerator.java:84)
    at com.optum.sample.dynamic.drl.RulesGenerator.main(RulesGenerator.java:42)
    Caused by: org.eclipse.aether.deployment.DeploymentException: Failed to deploy artifacts/metadata: Cannot access bs://mavenrepositorytest/snapshot with type default using the available connector factories: BasicRepositoryConnectorFactory
    at org.eclipse.aether.internal.impl.DefaultDeployer.deploy(DefaultDeployer.java:269)
    at org.eclipse.aether.internal.impl.DefaultDeployer.deploy(DefaultDeployer.java:245)
    at org.eclipse.aether.internal.impl.DefaultRepositorySystem.deploy(DefaultRepositorySystem.java:420)
    at org.appformer.maven.integration.MavenRepository.deployArtifact(MavenRepository.java:279)
    … 4 more
    Caused by: org.eclipse.aether.transfer.NoRepositoryConnectorException: Cannot access bs://mavenrepositorytest/snapshot with type default using the available connector factories: BasicRepositoryConnectorFactory
    at org.eclipse.aether.internal.impl.DefaultRepositoryConnectorProvider.newRepositoryConnector(DefaultRepositoryConnectorProvider.java:174)
    at org.eclipse.aether.internal.impl.DefaultDeployer.deploy(DefaultDeployer.java:265)
    … 7 more
    Caused by: org.eclipse.aether.transfer.NoRepositoryConnectorException: Cannot access bs://mavenrepositorytest/snapshot using the registered transporter factories: HttpTransporterFactory, FileTransporterFactory
    at org.eclipse.aether.connector.basic.BasicRepositoryConnector.(BasicRepositoryConnector.java:119)
    at org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory.newInstance(BasicRepositoryConnectorFactory.java:180)
    at org.eclipse.aether.internal.impl.DefaultRepositoryConnectorProvider.newRepositoryConnector(DefaultRepositoryConnectorProvider.java:113)
    … 8 more
    Caused by: org.eclipse.aether.transfer.NoTransporterException: Cannot access bs://mavenrepositorytest/snapshot using the registered transporter factories: HttpTransporterFactory, FileTransporterFactory
    at org.eclipse.aether.internal.impl.DefaultTransporterProvider.newTransporter(DefaultTransporterProvider.java:151)
    at org.eclipse.aether.connector.basic.BasicRepositoryConnector.(BasicRepositoryConnector.java:115)
    … 10 more

  9. can we use https instead bs protocal, I am seeing below error with bs
    Unsupported Protocol: ‘bs’: Cannot find wagon which supports the requested protocol: bs

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.