Skip to content

Commit

Permalink
Merge branch 'main' into dockerfile-proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
seicke authored Dec 7, 2024
2 parents 8b8c2bc + f51da9e commit 4e346a3
Show file tree
Hide file tree
Showing 41 changed files with 810 additions and 200 deletions.
141 changes: 141 additions & 0 deletions .github/workflows/docker-snapshot-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
name: Build and Push Docker Images on PR Merge

on:
push:
branches:
- main
paths-ignore:
- '.github/ISSUE_TEMPLATE/**'
- '.github/CODE_OF_CONDUCT.md'
- '.github/CODING_CONVENTIONS.md'
- '.github/CONTRIBUTING.md'
- '.github/dependabot.yml'
- '.github/pull_request_template.md'
- '.github/SECURITY.md'
- 'docs/**'
- 'examples/**'
- 'README.md'
- '.gitattributes'
- '.gitignore'
- 'LICENSE'
- 'NOTICE'

env:
DOCKER_NAMESPACE: eclipsebasyx

jobs:
build-and-push-prerelease:
runs-on: ubuntu-latest
strategy:
matrix:
include:
- name: aas-environment
path: basyx.aasenvironment/basyx.aasenvironment.component
- name: aas-repository
path: basyx.aasrepository/basyx.aasrepository.component
- name: submodel-repository
path: basyx.submodelrepository/basyx.submodelrepository.component
- name: conceptdescription-repository
path: basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository.component
- name: aas-discovery
path: basyx.aasdiscoveryservice/basyx.aasdiscoveryservice.component
- name: aasxfileserver
path: basyx.aasxfileserver/basyx.aasxfileserver.component
- name: aas-registry-kafka-mem
path: basyx.aasregistry/basyx.aasregistry-service-release-kafka-mem/src/main/docker
- name: aas-registry-kafka-mongodb
path: basyx.aasregistry/basyx.aasregistry-service-release-kafka-mongodb/src/main/docker
- name: aas-registry-log-mem
path: basyx.aasregistry/basyx.aasregistry-service-release-log-mem/src/main/docker
- name: aas-registry-log-mongodb
path: basyx.aasregistry/basyx.aasregistry-service-release-log-mongodb/src/main/docker
- name: submodel-registry-kafka-mem
path: basyx.submodelregistry/basyx.submodelregistry-service-release-kafka-mem/src/main/docker
- name: submodel-registry-kafka-mongodb
path: basyx.submodelregistry/basyx.submodelregistry-service-release-kafka-mongodb/src/main/docker
- name: submodel-registry-log-mem
path: basyx.submodelregistry/basyx.submodelregistry-service-release-log-mem/src/main/docker
- name: submodel-registry-log-mongodb
path: basyx.submodelregistry/basyx.submodelregistry-service-release-log-mongodb/src/main/docker

steps:
- name: Checkout Code
uses: actions/checkout@v4

- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: linux/amd64,linux/arm64,linux/arm/v7

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_HUB_USER }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: maven

- name: Build all modules first
run: mvn clean install -DskipTests

# Build the project
# For registry modules, we activate the dockerbuild profile and specify the module with --pl
- name: Build BaSyx
run: |
if [[ "${{ matrix.name }}" == *"registry"* ]]; then
# Derive the module's artifactId from the path
module_root=$(dirname "$(dirname "$(dirname "${{ matrix.path }}")")")
artifact_id=$(basename "$module_root")
# Run with dockerbuild profile and namespace
mvn clean install -DskipTests -Pdockerbuild "-Ddocker.namespace=${{ env.DOCKER_NAMESPACE }}" --pl "org.eclipse.digitaltwin.basyx:${artifact_id}"
else
echo "Non-registry module - already built in the previous step."
fi
- name: Prepare Registry JAR for Docker
if: contains(matrix.name, 'registry')
run: |
# Go three levels up from src/main/docker to get the module root
module_root=$(dirname "$(dirname "$(dirname "${{ matrix.path }}")")")
# Adjust the path to where the dockerbuild profile places the JAR
JAR_FILE=$(ls "$module_root/target/docker/${{ env.DOCKER_NAMESPACE }}/${{ matrix.name }}/2.0.0-SNAPSHOT/build/maven/"*.jar | head -n 1)
if [ -z "$JAR_FILE" ]; then
echo "No repackaged JAR found in $module_root/target/docker/${{ env.DOCKER_NAMESPACE }}/${{ matrix.name }}/2.0.0-SNAPSHOT/build/maven. Check your build."
exit 1
fi
# Create the maven directory inside the Docker context and copy the JAR there
mkdir -p "${{ matrix.path }}/maven"
cp "$JAR_FILE" "${{ matrix.path }}/maven/"
# Extract the final name without .jar extension
FINAL_NAME=$(basename "$JAR_FILE" .jar)
echo "FINAL_ARGS=FINAL_NAME=${FINAL_NAME}" >> $GITHUB_ENV
- name: No-Op for Non-Registry Modules
if: "!contains(matrix.name, 'registry')"
run: echo "FINAL_ARGS=" >> $GITHUB_ENV

- name: Build and Push Docker Image
uses: docker/build-push-action@v6
with:
context: ${{ matrix.path }}
file: ${{ matrix.path }}/Dockerfile
push: true
platforms: linux/amd64,linux/arm64,linux/arm/v7
tags: |
${{ env.DOCKER_NAMESPACE }}/${{ matrix.name }}:2.0.0-SNAPSHOT
build-args: ${{ env.FINAL_ARGS }}

- name: Verify Docker Image
run: |
docker pull ${{ env.DOCKER_NAMESPACE }}/${{ matrix.name }}:2.0.0-SNAPSHOT
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.eclipse.digitaltwin.basyx.aasdiscoveryservice.http;

import java.util.List;
import java.util.TreeSet;

import org.eclipse.digitaltwin.basyx.http.description.Profile;
import org.eclipse.digitaltwin.basyx.http.description.ProfileDeclaration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AasDiscoveryServiceDescriptionConfiguration {
@Bean
public ProfileDeclaration aasDiscoveryProfiles() {
return () -> new TreeSet<>(List.of(Profile.DISCOVERYSERVICESPECIFICATION_SSP_001));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@ static ObjectMapper buildObjectMapper() {
static AasDescriptorFactory buildAasDescriptorFactory(String... aasRepositoryBaseUrls) {
AttributeMapper attributeMapper = new AttributeMapper(objectMapper);

return new AasDescriptorFactory(null, List.of(aasRepositoryBaseUrls), attributeMapper);
return new AasDescriptorFactory(List.of(aasRepositoryBaseUrls), attributeMapper);
}

static SubmodelDescriptorFactory buildSmDescriptorFactory(String... aasRepositoryBaseUrls) {
org.eclipse.digitaltwin.basyx.submodelregistry.client.mapper.AttributeMapper attributeMapperSm = new org.eclipse.digitaltwin.basyx.submodelregistry.client.mapper.AttributeMapper(
objectMapper);
return new SubmodelDescriptorFactory(null, List.of(aasRepositoryBaseUrls), attributeMapperSm);
return new SubmodelDescriptorFactory(List.of(aasRepositoryBaseUrls), attributeMapperSm);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/*******************************************************************************
* Copyright (C) 2024 the Eclipse BaSyx Authors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* SPDX-License-Identifier: MIT
******************************************************************************/

package org.eclipse.digitaltwin.basyx.aasenvironment.client;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.IntStream;

import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell;
import org.eclipse.digitaltwin.aas4j.v3.model.Key;
import org.eclipse.digitaltwin.aas4j.v3.model.Reference;
import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultAssetAdministrationShell;
import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultSubmodel;
import org.eclipse.digitaltwin.basyx.aasregistry.client.api.RegistryAndDiscoveryInterfaceApi;
import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository;
import org.eclipse.digitaltwin.basyx.aasrepository.client.ConnectedAasRepository;
import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo;
import org.eclipse.digitaltwin.basyx.submodelregistry.client.api.SubmodelRegistryApi;
import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepository;
import org.eclipse.digitaltwin.basyx.submodelrepository.client.ConnectedSubmodelRepository;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ConfigurableApplicationContext;

public class TestConnectedAasManagerMultithreading {
static final String AAS_REPOSITORY_BASE_PATH = "http://localhost:8081";
static final String SM_REPOSITORY_BASE_PATH = "http://localhost:8081";
static final String AAS_REGISTRY_BASE_PATH = "http://localhost:8050";
static final String SM_REGISTRY_BASE_PATH = "http://localhost:8060";
static final int N_THREADS = 20;

static ConfigurableApplicationContext appContext;
static AasRepository aasRepository;
static SubmodelRepository smRepository;

static ConnectedAasRepository connectedAasRepository;
static ConnectedSubmodelRepository connectedSmRepository;
static RegistryAndDiscoveryInterfaceApi aasRegistryApi;
static SubmodelRegistryApi smRegistryApi;

static ConnectedAasManager aasManager;

@BeforeClass
public static void setupRepositories() {
appContext = new SpringApplication(DummyAasEnvironmentComponent.class).run(new String[] {});

connectedAasRepository = new ConnectedAasRepository(AAS_REPOSITORY_BASE_PATH);
connectedSmRepository = new ConnectedSubmodelRepository(SM_REPOSITORY_BASE_PATH);
aasRegistryApi = new RegistryAndDiscoveryInterfaceApi(AAS_REGISTRY_BASE_PATH);
smRegistryApi = new SubmodelRegistryApi(SM_REGISTRY_BASE_PATH);
aasManager = new ConnectedAasManager(AAS_REGISTRY_BASE_PATH, AAS_REPOSITORY_BASE_PATH, SM_REGISTRY_BASE_PATH, SM_REPOSITORY_BASE_PATH);

cleanUpRegistries();
}

@After
public void cleanUpComponents() {
cleanUpRegistries();
}

@AfterClass
public static void stopContext() {
appContext.close();
}

@Test
public void testParallelSubmodelCreation() throws ExecutionException, InterruptedException {
AssetAdministrationShell shell = createShell();

ExecutorService executorService = Executors.newFixedThreadPool(N_THREADS);
ConcurrentLinkedDeque<String> createdSubmodelIds = new ConcurrentLinkedDeque<>();

List<Future<Boolean>> futures = IntStream.range(0, N_THREADS).mapToObj(i -> executorService.submit(() -> createdSubmodelIds.add(createSubmodel(shell.getId(), i)))).toList();

try {
for (int i = 0; i < N_THREADS; i++) {
futures.get(i).get();
}
} finally {
executorService.shutdown();
}

createdSubmodelIds.forEach(submodelId -> assertSubmodelWasCreatedAndRegistered(shell.getId(), submodelId));
}

static void assertSubmodelWasCreatedAndRegistered(String shellId, String submodelId) {
assertEquals(submodelId, aasManager.getSubmodelService(submodelId).getSubmodel().getId());
assertTrue(connectedAasRepository.getSubmodelReferences(shellId, PaginationInfo.NO_LIMIT).getResult().stream().map(Reference::getKeys).flatMap(Collection::stream).map(Key::getValue).anyMatch(submodelId::equals));
}


private static void cleanUpRegistries() {
try {
aasRegistryApi.deleteAllShellDescriptors();
} catch (Exception e) {
System.out.println(e.getMessage());
}
try {
smRegistryApi.deleteAllSubmodelDescriptors();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}

private static AssetAdministrationShell createShell() {
String id = UUID.randomUUID().toString();
DefaultAssetAdministrationShell shell = new DefaultAssetAdministrationShell.Builder().id(id).build();
aasManager.createAas(shell);
return aasManager.getAasService(id).getAAS();
}

private static String createSubmodel(String aasId, int threadId) {
try {
String id = aasId + "-thread" + threadId;
DefaultSubmodel submodel = new DefaultSubmodel.Builder().id(id).build();
aasManager.createSubmodelInAas(aasId, submodel);
return id;
} catch (Exception e) {
throw new RuntimeException("Failed at thread " + threadId, e);
}
}

}
2 changes: 1 addition & 1 deletion basyx.aasenvironment/basyx.aasenvironment-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.2.1-jre</version>
<version>33.3.1-jre</version>
</dependency>

<dependency>
Expand Down
Loading

0 comments on commit 4e346a3

Please sign in to comment.