GithubHelp home page GithubHelp logo

j3t / mvnio Goto Github PK

View Code? Open in Web Editor NEW
2.0 2.0 1.0 337 KB

Repository for Maven artifacts which uses S3 buckets as storage provider.

License: Apache License 2.0

Java 100.00%
maven-repository maven s3-bucket minio s3 reactive-streams nonblocking backpressure

mvnio's Introduction

CI Docker Tags Quality Gate Status

mvnio is a horizontal scalable Maven Repository Manager with first class support for S3 buckets.

The underlying webserver is implemented with reactive streams, or more specific by using Spring webflux which uses project-reactor under the hood. For the S3 bucket interaction, the Amazon Async S3 client library is used, which is also a non-blocking API, and it has support for other S3 compatible storage providers as well (e.g. MinIO).

Motivation

There are plenty of Maven Repository Managers and they are great and have a lot of features, but most of them don't support S3 buckets at all or not very well or require a special license.

As alternative, you could use a so called maven-wagon which basically adds S3 bucket support to the maven client. There are also plenty of them (1, 2, 3, ...), but they require an extra configuration, which in fact often is not supported by third-party products. For example Jenkins picks not up the extra configuration (see https://issues.jenkins-ci.org/browse/JENKINS-30058). They also cannot take into account that Maven artifacts are immutable. You could lock the objects in S3 but then the metadata cannot be updated anymore.

Features

  • Standard Repository Layout
  • upload and download artifacts
  • browse artifacts and retrieve metadata easily
  • stateless and horizontal scalable
  • support for any S3 compatible storage provider
  • multiple repositories
  • immutability protection
  • quick startup time and less memory consumption

How it Works

The diagram below shows how mvnio handles maven client requests and how they are mapped to the S3 storage provider.

Architecture

In general, a maven client interacts with a maven repository when it tries to install an artifact with a GET request and with a PUT request when it wants to deploy an artifact. For example, when a client requests GET /maven/releases/foo/bar/1.0.1/bar-1.0.1.pom from mvnio then mvnio tries to get an object with key foo/bar/1.0.1/bar-1.0.1.pom in bucket releases from S3.

The AppTests and the corresponding requests and responses could also be helpful if you want more details.

Configuration

AppProperties contains a list of all available configuration parameters, and their default values.

Security

mvnio expects a Basic Authorization Header sent along with any client request. The header contains the S3 Credentials of the corresponding S3 Bucket. It also requires the following permissions:

  • s3:GetObject - to download artifacts
  • s3:HeadObject and s3:PutObject - to upload artifacts
  • s3:ListBucket- to request metadata or to list versions (optional)

Note: Clients can bypass the repository and modify artifacts in S3 directly!

Getting started

This example shows how mvnio can be set up with MinIO as storage provider. It requires docker-compose and mvn installed properly and, for sake of simplicity, the MinIO admin user will be used to connect to S3/MinIO. For production environments you should use an extra user with strong credentials, and the minimum required permissions (see Security)!

Let's get started:

  • run docker-compose up to start up mvnio and MinIO as well (ports: 8080 and 9000)
  • run docker-compose run --rm mc config host add minio http://minio:9000 admin long-password once to register MinIO
  • run docker-compose run --rm mc mb minio/releases to create a bucket named releases
  • adjust your ~/.m2/settings.xml:
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
  <servers>
    <server>
      <id>maven-releases</id>
      <username>admin</username>
      <password>long-password</password>
    </server>
  </servers>
</settings>
  • create a file named pom.xml in an empty directory with the following content:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>foo</groupId>
    <artifactId>bar</artifactId>
    <version>1.0.1</version>

    <distributionManagement>
        <repository>
            <id>maven-releases</id>
            <url>http://localhost:8080/maven/releases</url>
        </repository>
    </distributionManagement>
</project>
  • run mvn deploy
...
[INFO] --- maven-deploy-plugin:2.7:deploy (default-deploy) @ bar ---
Uploading to maven-releases: http://localhost:8080/maven/releases/foo/bar/1.0.1/bar-1.0.1.jar
Uploaded to maven-releases: http://localhost:8080/maven/releases/foo/bar/1.0.1/bar-1.0.1.jar (1.4 kB at 1.1 kB/s)
Uploading to maven-releases: http://localhost:8080/maven/releases/foo/bar/1.0.1/bar-1.0.1.pom
Uploaded to maven-releases: http://localhost:8080/maven/releases/foo/bar/1.0.1/bar-1.0.1.pom (601 B at 5.1 kB/s)
Downloading from maven-releases: http://localhost:8080/maven/releases/foo/bar/maven-metadata.xml
Uploading to maven-releases: http://localhost:8080/maven/releases/foo/bar/maven-metadata.xml
Uploaded to maven-releases: http://localhost:8080/maven/releases/foo/bar/maven-metadata.xml (286 B at 2.1 kB/s)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.917 s
[INFO] Finished at: 2020-10-23T13:22:45+02:00
[INFO] Final Memory: 12M/209M
[INFO] ------------------------------------------------------------------------

The artifacts should now be available in MinIO.

Roadmap

  • mirror for central (light version, just proxy the request)
  • alternative user/account management
    • independent of S3
    • central configuration (via vault for example)
    • storage provider is configurable per repository
    • proxy/mirror for repositories (central and external)

Pitfalls

  • users accessKey/secretKey in S3, are used as username/password in Maven (see ~/.m2/settings.xml)
  • users can bypass the repository and access objects directly in S3

Further reading

mvnio's People

Contributors

dependabot[bot] avatar j3t avatar

Stargazers

 avatar

Watchers

 avatar  avatar

mvnio's Issues

Maven upload process stuck

If you try to upload an artifact but the reposiorty/bucket not exists then the upload gets stuck. At the same time, the load on the server increases dramatically.

Client log:

% mvn deploy
[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] Building bar 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ bar ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /Users/j3t/Development/repos/example/src/main/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ bar ---
[INFO] No sources to compile
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ bar ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /Users/j3t/Development/repos/example/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ bar ---
[INFO] No sources to compile
[INFO] 
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ bar ---
[INFO] No tests to run.
[INFO] 
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ bar ---
[WARNING] JAR will be empty - no content was marked for inclusion!
[INFO] 
[INFO] --- maven-install-plugin:2.4:install (default-install) @ bar ---
[INFO] Installing /Users/j3t/Development/repos/example/target/bar-1.0-SNAPSHOT.jar to /Users/j3t/.m2/repository/foo/bar/1.0-SNAPSHOT/bar-1.0-SNAPSHOT.jar
[INFO] Installing /Users/j3t/Development/repos/example/pom.xml to /Users/j3t/.m2/repository/foo/bar/1.0-SNAPSHOT/bar-1.0-SNAPSHOT.pom
[INFO] 
[INFO] --- maven-deploy-plugin:2.7:deploy (default-deploy) @ bar ---
Downloading from maven-snapshots: http://localhost:8181/maven/snapshots/foo/bar/1.0-SNAPSHOT/maven-metadata.xml
Uploading to maven-snapshots: http://localhost:8181/maven/snapshots/foo/bar/1.0-SNAPSHOT/bar-1.0-20201023.101727-1.jar

Server log:

mvnio_1  | 2020-10-23 10:10:11.058  INFO 1 --- [           main] com.github.j3t.mvnio.App                 : Starting App on e1189541e6a3 with PID 1 (/workspace/BOOT-INF/classes started by cnb in /workspace)
mvnio_1  | 2020-10-23 10:10:11.065  INFO 1 --- [           main] com.github.j3t.mvnio.App                 : No active profile set, falling back to default profiles: default
mvnio_1  | 2020-10-23 10:10:14.096  INFO 1 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port(s): 8080
mvnio_1  | 2020-10-23 10:10:14.117  INFO 1 --- [           main] com.github.j3t.mvnio.App                 : Started App in 3.892 seconds (JVM running for 4.846)
mvnio_1  | 2020-10-23 10:17:26.838  INFO 1 --- [or-http-epoll-2] com.github.j3t.mvnio.error.ErrorHandler  : status: 401, message: Not authorized, access to repository (snapshots) denied
mvnio_1  | 2020-10-23 10:17:27.424  INFO 1 --- [nc-response-0-0] com.github.j3t.mvnio.error.ErrorHandler  : status: 404, message: The specified bucket does not exist (Service: S3, Status Code: 404, Request ID: 164097AF7B98BBEC, Extended Request ID: null)

No permission results in error 500

When you request a resource, that is not available in Minio, and you don't have permission to search through it, it returns 500.
This is not ideal, because it breaks all other dependencies, which have never been on that maven repository.

[-response-0-413] com.github.j3t.mvnio.error.ErrorHandler  : status: 500, message: Access Denied. (Service: S3, Status Code: 403, Request ID: 1728727D7328E8C9)

software.amazon.awssdk.services.s3.model.S3Exception: Access Denied. (Service: S3, Status Code: 403, Request ID: 1728727D7328E8C9)
	at software.amazon.awssdk.services.s3.model.S3Exception$BuilderImpl.build(S3Exception.java:95) ~[s3-2.17.219.jar:na]
	Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
	*__checkpoint ? Handler com.github.j3t.mvnio.maven.RepositoryController#download(String, String) [DispatcherHandler]
Original Stack Trace:
		at software.amazon.awssdk.services.s3.model.S3Exception$BuilderImpl.build(S3Exception.java:95) ~[s3-2.17.219.jar:na]
		at software.amazon.awssdk.services.s3.model.S3Exception$BuilderImpl.build(S3Exception.java:55) ~[s3-2.17.219.jar:na]
		at software.amazon.awssdk.protocols.query.internal.unmarshall.AwsXmlErrorUnmarshaller.unmarshall(AwsXmlErrorUnmarshaller.java:99) ~[aws-query-protocol-2.17.219.jar:na]
		at software.amazon.awssdk.protocols.query.unmarshall.AwsXmlErrorProtocolUnmarshaller.handle(AwsXmlErrorProtocolUnmarshaller.java:102) ~[aws-query-protocol-2.17.219.jar:na]
		at software.amazon.awssdk.protocols.query.unmarshall.AwsXmlErrorProtocolUnmarshaller.handle(AwsXmlErrorProtocolUnmarshaller.java:82) ~[aws-query-protocol-2.17.219.jar:na]
		at software.amazon.awssdk.core.http.MetricCollectingHttpResponseHandler.lambda$handle$0(MetricCollectingHttpResponseHandler.java:52) ~[sdk-core-2.17.219.jar:na]
		at software.amazon.awssdk.core.internal.util.MetricUtils.measureDurationUnsafe(MetricUtils.java:63) ~[sdk-core-2.17.219.jar:na]
		at software.amazon.awssdk.core.http.MetricCollectingHttpResponseHandler.handle(MetricCollectingHttpResponseHandler.java:52) ~[sdk-core-2.17.219.jar:na]
		at software.amazon.awssdk.core.internal.http.async.AsyncResponseHandler.lambda$prepare$0(AsyncResponseHandler.java:89) ~[sdk-core-2.17.219.jar:na]
		at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(Unknown Source) ~[na:na]
		at java.base/java.util.concurrent.CompletableFuture.postComplete(Unknown Source) ~[na:na]
		at java.base/java.util.concurrent.CompletableFuture.complete(Unknown Source) ~[na:na]
		at software.amazon.awssdk.core.internal.http.async.AsyncResponseHandler$BaosSubscriber.onComplete(AsyncResponseHandler.java:132) ~[sdk-core-2.17.219.jar:na]
		at software.amazon.awssdk.http.nio.netty.internal.ResponseHandler$DataCountingPublisher$1.onComplete(ResponseHandler.java:513) ~[netty-nio-client-2.17.219.jar:na]
		at software.amazon.awssdk.http.nio.netty.internal.ResponseHandler.runAndLogError(ResponseHandler.java:250) ~[netty-nio-client-2.17.219.jar:na]
		at software.amazon.awssdk.http.nio.netty.internal.ResponseHandler.access$600(ResponseHandler.java:75) ~[netty-nio-client-2.17.219.jar:na]
		at software.amazon.awssdk.http.nio.netty.internal.ResponseHandler$PublisherAdapter$1.onComplete(ResponseHandler.java:371) ~[netty-nio-client-2.17.219.jar:na]
		at software.amazon.awssdk.http.nio.netty.internal.nrs.HandlerPublisher.publishMessage(HandlerPublisher.java:402) ~[netty-nio-client-2.17.219.jar:na]
		at software.amazon.awssdk.http.nio.netty.internal.nrs.HandlerPublisher.flushBuffer(HandlerPublisher.java:338) ~[netty-nio-client-2.17.219.jar:na]
		at software.amazon.awssdk.http.nio.netty.internal.nrs.HandlerPublisher.receivedDemand(HandlerPublisher.java:291) ~[netty-nio-client-2.17.219.jar:na]
		at software.amazon.awssdk.http.nio.netty.internal.nrs.HandlerPublisher.access$200(HandlerPublisher.java:61) ~[netty-nio-client-2.17.219.jar:na]
		at software.amazon.awssdk.http.nio.netty.internal.nrs.HandlerPublisher$ChannelSubscription$1.run(HandlerPublisher.java:495) ~[netty-nio-client-2.17.219.jar:na]
		at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:174) ~[netty-common-4.1.78.Final.jar:4.1.78.Final]
		at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:167) ~[netty-common-4.1.78.Final.jar:4.1.78.Final]
		at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470) ~[netty-common-4.1.78.Final.jar:4.1.78.Final]
		at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500) ~[netty-transport-4.1.78.Final.jar:4.1.78.Final]
		at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) ~[netty-common-4.1.78.Final.jar:4.1.78.Final]
		at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.78.Final.jar:4.1.78.Final]
		at java.base/java.lang.Thread.run(Unknown Source) ~[na:na]```

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.