Skip to content

Commit 1e52464

Browse files
committed
Refactor artifact management
1 parent c0f03e4 commit 1e52464

File tree

98 files changed

+1318
-1719
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

98 files changed

+1318
-1719
lines changed

.3rd-party/README.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1-
# Third-Party Dependencies
1+
Third-Party Dependencies
2+
===
23

3-
This folder provides listings of all 3rd-party dependencies incl. their licenses. There is a dedicated subfolder for
4-
each release (and milestone) holding the release-specific information.
4+
This folder contains DEPENDENCIES that has the list of all 3rd-party dependencies (including transitive) with their licenses and approval status. Each release (and milestone) holds the release-specific information.
55

6-
The DEPENDENCIES file could be generated manually using [Eclipse Dash License Tool](https://github.com/eclipse/dash-licenses) maven plugin by running in root folder:
6+
DEPENDENCIES file is generated (automatically and committed) by [../.github/workflows/reusable_workflow_license-scan.yaml](../.github/workflows/reusable_workflow_license-scan.yaml) during the release process ([../.github/workflows/release.yaml](../.github/workflows/release.yaml)) and on daily basis ([../.github/workflows/license-scan.yaml](../.github/workflows/license-scan.yaml)). It is also
7+
8+
DEPENDENCIES file could be generated manually using [Eclipse Dash License Tool](https://github.com/eclipse/dash-licenses) maven plugin by running:
9+
```shell
10+
$ cd .. && mvn license-tool:license-check -Ddash.fail=false -PcheckLicense
11+
```
12+
13+
Note: Some projects (e.g. test artifacts) could be excluded with *--projects* parameter, e.g:
714
```shell
8-
mvn clean install -PcheckLicense -DskipTests \
9-
--projects '!org.eclipse.hawkbit:hawkbit-repository-test,!org.eclipse.hawkbit:hawkbit-dmf-rabbitmq-test'
15+
$ cd .. && mvn license-tool:license-check -Ddash.fail=false -PcheckLicense \ --projects '!org.eclipse.hawkbit:hawkbit-repository-test,!org.eclipse.hawkbit:hawkbit-dmf-rabbitmq-test'
1016
```

.github/workflows/reusable_workflow_license-scan.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ jobs:
5050
- name: Check dependency licenses with dash tool (and open issues to Dash IP lab, doesn't fail)
5151
if: ${{ inputs.open_tickets }}
5252
run: |
53-
mvn license-tool:license-check -Ddash.fail=false -PcheckLicense -Ddash.iplab.token=${GITLAB_API_TOKEN} --projects '!org.eclipse.hawkbit:hawkbit-repository-test,!org.eclipse.hawkbit:hawkbit-dmf-rabbitmq-test'
53+
mvn license-tool:license-check -Ddash.fail=false -PcheckLicense -Ddash.iplab.token=${GITLAB_API_TOKEN}
5454
CHANGED_FILES_COUNT=$(git status --short | wc -l)
5555
CHANGED_FILES_COUNT=${CHANGED_FILES_COUNT//[[:space:]]/}
5656
echo "Number of changed files: ${CHANGED_FILES_COUNT}"

docker/README.md

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,33 @@
11
hawkBit Docker
22
===
33

4-
# Setup
4+
## Overview
5+
This folder contains example Docker build and Docker Compose files to build and start the hawkBit as monolith or as microservices.
56

6-
## A: Docker Container
7-
Start the hawkBit Update Server as a single container (requires Docker to be installed and all dependencies to be available)
7+
## Build
8+
You could build the hawkbit Docker images following the [README.md](build/README.md) instructions.
9+
10+
## Start
11+
You can start hawkbit as a Docker Container (only monolith) or with Docker Compose
12+
13+
#### A: Docker Container (only as monolith)
14+
_Note: You need to have Docker installed on your machine._
15+
16+
Start the hawkBit Update Server (monolith) as a single container (with embedded H2, if you configure a different database, e.g. MySQL or PostgreSQL, you should start it separately):
817

918
```bash
1019
$ docker run -d -p 8080:8080 hawkbit/hawkbit-update-server:latest
1120
```
1221

13-
## B: Docker Compose
14-
Start the hawkBit Update Server together with an MySQL and RabbitMQ instance as containers (Requires Docker Compose to be installed)
22+
### B: Docker Compose
23+
_Note: You need to have Docker Compose installed on your machine._
24+
25+
Start the hawkBit Update Server (monolith) together with an MySQL and RabbitMQ instance as containers (Requires Docker Compose to be installed)
1526

1627
```bash
1728
$ docker compose -f mysql/docker-compose-monolith-mysql.yml up
1829
```
19-
You could, also start it in different flavours, with UI or in microservices mode.
20-
21-
Note: Whit the upper command CTRL+C shuts down all services. Add '-d' at the end to start all into detached mode:
30+
With the upper command CTRL+C shuts down all services. Add '-d' at the end to start all into detached mode:
2231
```bash
2332
$ docker compose -f mysql/docker-compose-monolith-mysql.yml up -d
2433
```
@@ -27,15 +36,20 @@ Then stop all services with:
2736
$ docker compose -f mysql/docker-compose-monolith-mysql.yml down
2837
```
2938

30-
# Access
31-
| Service / Container | URL | Login | A | B | C |
32-
|--------------------------|--------------------------------------------------|-------------|----------|----------|----------|
33-
| hawkBit Update Server | [http://localhost:8080/](http://localhost:8080/) | admin:admin | ✓ | ✓ | ✓ |
34-
| MySQL | localhost:3306/hawkbit | root | | ✓ | ✓ |
35-
| RabbitMQ | [http://localhost:15672](http://localhost:15672) | guest:guest | | ✓ | ✓ |
39+
You could, also start it in different flavours, with UI or in microservices mode (see Docker Compose files in [mysql](./mysql) and [postgres](./postgres) folders). For instance to start with PostgreSQL, with RabbitMQ, in microservices mode and with UI you could use:
40+
```bash
41+
$ docker compose -f postgres/docker-compose-micro-services-with-simple-ui-postgres.yml up
42+
```
3643

37-
# Configuration
38-
You can override application.properties by setting an environment variable SPRING_APPLICATION_JSON for hawkbit container.
44+
### Access
45+
| Service / Container | URL | Login | A | B |
46+
|-----------------------|------------------------|-------------|----------|----------|
47+
| hawkBit Update Server | [http://localhost:8080/](http://localhost:8080/) | admin:admin | ✓ | ✓ |
48+
| MySQL | localhost:3306/hawkbit | root | | ✓ |
49+
| RabbitMQ | [http://localhost:15672](http://localhost:15672) | guest:guest | | ✓ |
50+
51+
### Configuration
52+
You can override _application.properties_ by setting an environment variable _SPRING_APPLICATION_JSON_ to the hawkbit container, e.g.:
3953

4054
```yaml
4155
hawkbit:
@@ -55,4 +69,4 @@ hawkbit:
5569
"hawkbit.security.user.hawkbit.password": "{noop}isAwesome!",
5670
"hawkbit.security.user.hawkbit.roles": "TENANT_ADMIN"
5771
}'
58-
```
72+
```

docker/build/README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@ Docker image could be build, for example, with (fixed version 0.4.1 is just an e
2828
```shell
2929
docker build --build-arg HAWKBIT_APP=hawkbit-update-server --build-arg HAWKBIT_VERSION=0.4.1 -t hawkbit_update_server:0.4.1 . -f Dockerfile
3030
```
31-
3231
or just by:
33-
3432
```shell
3533
docker build --build-arg HAWKBIT_VERSION=0.4.1 -t hawkbit_update_server:0.4.1 .
3634
```

hawkbit-artifact/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
hawkBit Artifact
2+
===
3+
The module contains internal modules for artifact storage and encryption:
4+
* [hawkbit-artifact-api](hawkbit-artifact-api/README.md) - see for artifact API module
5+
* [hawkbit-artifact-fs](hawkbit-artifact-fs/README.md) - see for file-system based artifact storage implementation
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1-
# hawkBit Artifact API
2-
3-
Various internal interfaces artifact API classes.
1+
hawkBit Artifact API
2+
===
3+
The module contains artifact API classes supporting following main concepts:
4+
* Artifact Storage - represented by the [ArtifactStorage](src/main/java/org/eclipse/hawkbit/artifact/ArtifactStorage.java) interface. It serves for artifact binary store operations
5+
* Artifact Encryption - represented by the [ArtifactEncryptionService](src/main/java/org/eclipse/hawkbit/artifact/encryption/ArtifactEncryptionService.java). It is a pluggable implementation of artifact encryption operations.
6+
* Artifact URL handling - represented by[ArtifactUrlResolver](src/main/java/org/eclipse/hawkbit/artifact/urlresolver/ArtifactUrlResolver.java) interface. It provides resolving URLs to the artifacts. The module provides a simple property based implementation ([PropertyBasedArtifactUrlResolver](src/main/java/org/eclipse/hawkbit/artifact/urlresolver/PropertyBasedArtifactUrlResolver.java))
Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
/**
2-
* Copyright (c) 2025 Bosch Digital GmbH, Germany. All rights reserved.
2+
* Copyright (c) 2025 Contributors to the Eclipse Foundation
3+
*
4+
* This program and the accompanying materials are made
5+
* available under the terms of the Eclipse Public License 2.0
6+
* which is available at https://www.eclipse.org/legal/epl-2.0/
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
39
*/
4-
package org.eclipse.hawkbit.repository.artifact;
10+
package org.eclipse.hawkbit.artifact;
511

612
import java.io.BufferedOutputStream;
713
import java.io.File;
@@ -16,27 +22,27 @@
1622
import java.util.HexFormat;
1723

1824
import lombok.extern.slf4j.Slf4j;
19-
import org.eclipse.hawkbit.repository.artifact.exception.ArtifactStoreException;
20-
import org.eclipse.hawkbit.repository.artifact.exception.HashNotMatchException;
21-
import org.eclipse.hawkbit.repository.artifact.model.AbstractDbArtifact;
22-
import org.eclipse.hawkbit.repository.artifact.model.DbArtifactHash;
25+
import org.eclipse.hawkbit.artifact.exception.ArtifactStoreException;
26+
import org.eclipse.hawkbit.artifact.exception.HashNotMatchException;
27+
import org.eclipse.hawkbit.artifact.model.ArtifactHashes;
28+
import org.eclipse.hawkbit.artifact.model.StoredArtifactInfo;
2329
import org.springframework.util.ObjectUtils;
2430

2531
/**
2632
* Abstract utility class for ArtifactRepository implementations with common functionality, e.g. computation of hashes.
2733
*/
2834
@Slf4j
29-
public abstract class AbstractArtifactRepository implements ArtifactRepository {
35+
public abstract class AbstractArtifactStorage implements ArtifactStorage {
3036

3137
private static final String TEMP_FILE_PREFIX = "tmp";
3238
private static final String TEMP_FILE_SUFFIX = "artifactrepo";
3339

3440
// suppress warning, of not strong enough hashing algorithm, SHA-1 and MD5 is not used security related
3541
@SuppressWarnings("squid:S2070")
3642
@Override
37-
public AbstractDbArtifact store(
43+
public StoredArtifactInfo store(
3844
final String tenant, final InputStream content, final String filename, final String contentType,
39-
final DbArtifactHash providedHashes) {
45+
final ArtifactHashes providedHashes) {
4046
final MessageDigest mdSHA1;
4147
final MessageDigest mdMD5;
4248
final MessageDigest mdSHA256;
@@ -54,19 +60,19 @@ public AbstractDbArtifact store(
5460

5561
final HexFormat hexFormat = HexFormat.of().withLowerCase();
5662

57-
final String sha1Hash16 = hexFormat.formatHex(mdSHA1.digest());
58-
final String md5Hash16 = hexFormat.formatHex(mdMD5.digest());
59-
final String sha256Hash16 = hexFormat.formatHex(mdSHA256.digest());
63+
final String sha1Hash = hexFormat.formatHex(mdSHA1.digest());
64+
final String md5Hash = hexFormat.formatHex(mdMD5.digest());
65+
final String sha256Hash = hexFormat.formatHex(mdSHA256.digest());
6066

61-
checkHashes(providedHashes, sha1Hash16, md5Hash16, sha256Hash16);
67+
checkHashes(providedHashes, sha1Hash, md5Hash, sha256Hash);
6268

6369
// Check if file with same sha1 hash exists and if so return it
64-
if (existsBySha1(tenant, sha1Hash16)) {
70+
if (existsBySha1(tenant, sha1Hash)) {
6571
// TODO - shall check if the file is really the same as bytes or just sha1 hash is the same
66-
return addMissingHashes(getBySha1(tenant, sha1Hash16), sha1Hash16, md5Hash16, sha256Hash16);
72+
return new StoredArtifactInfo(contentType, tempFile.length(), new ArtifactHashes(sha1Hash, md5Hash, sha256Hash));
6773
}
6874

69-
return store(sanitizeTenant(tenant), new DbArtifactHash(sha1Hash16, md5Hash16, sha256Hash16), contentType, tempFile);
75+
return store(sanitizeTenant(tenant), new ArtifactHashes(sha1Hash, md5Hash, sha256Hash), contentType, tempFile);
7076
} catch (final IOException e) {
7177
throw new ArtifactStoreException(e.getMessage(), e);
7278
} finally {
@@ -98,8 +104,8 @@ protected String storeTempFile(final InputStream content) throws IOException {
98104
return file.getPath();
99105
}
100106

101-
protected abstract AbstractDbArtifact store(final String tenant, final DbArtifactHash base16Hashes,
102-
final String contentType, final String tempFile) throws IOException;
107+
protected abstract StoredArtifactInfo store(
108+
final String tenant, final ArtifactHashes base16Hashes, final String contentType, final String tempFile) throws IOException;
103109

104110
// java:S1066 - more readable with separate "if" statements
105111
// java:S4042 - delete reason is not needed
@@ -132,8 +138,8 @@ public static File createTempFile(final boolean directory) {
132138
}
133139
}
134140

135-
private static void checkHashes(final DbArtifactHash providedHashes,
136-
final String sha1Hash16, final String md5Hash16, final String sha256Hash16) {
141+
private static void checkHashes(
142+
final ArtifactHashes providedHashes, final String sha1Hash16, final String md5Hash16, final String sha256Hash16) {
137143
if (providedHashes == null) {
138144
return;
139145
}
@@ -161,16 +167,6 @@ private static DigestInputStream wrapInDigestInputStream(final InputStream input
161167
return new DigestInputStream(new DigestInputStream(new DigestInputStream(input, mdSHA256), mdMD5), mdSHA1);
162168
}
163169

164-
private AbstractDbArtifact addMissingHashes(final AbstractDbArtifact existing,
165-
final String calculatedSha1, final String calculatedMd5, final String calculatedSha256) {
166-
final String sha1 = checkEmpty(existing.getHashes().sha1(), calculatedSha1);
167-
final String md5 = checkEmpty(existing.getHashes().md5(), calculatedMd5);
168-
final String sha256 = checkEmpty(existing.getHashes().sha256(), calculatedSha256);
169-
170-
existing.setHashes(new DbArtifactHash(sha1, md5, sha256));
171-
return existing;
172-
}
173-
174170
private String checkEmpty(final String value, final String fallback) {
175171
return ObjectUtils.isEmpty(value) ? fallback : value;
176172
}
Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,29 @@
11
/**
2-
* Copyright (c) 2025 Bosch Digital GmbH, Germany. All rights reserved.
2+
* Copyright (c) 2025 Contributors to the Eclipse Foundation
3+
*
4+
* This program and the accompanying materials are made
5+
* available under the terms of the Eclipse Public License 2.0
6+
* which is available at https://www.eclipse.org/legal/epl-2.0/
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
39
*/
4-
package org.eclipse.hawkbit.repository.artifact;
10+
package org.eclipse.hawkbit.artifact;
511

612
import java.io.InputStream;
713

814
import jakarta.validation.constraints.NotEmpty;
915
import jakarta.validation.constraints.NotNull;
1016

11-
import org.eclipse.hawkbit.repository.artifact.exception.ArtifactBinaryNotFoundException;
12-
import org.eclipse.hawkbit.repository.artifact.exception.ArtifactStoreException;
13-
import org.eclipse.hawkbit.repository.artifact.exception.HashNotMatchException;
14-
import org.eclipse.hawkbit.repository.artifact.model.AbstractDbArtifact;
15-
import org.eclipse.hawkbit.repository.artifact.model.DbArtifactHash;
17+
import org.eclipse.hawkbit.artifact.exception.ArtifactBinaryNotFoundException;
18+
import org.eclipse.hawkbit.artifact.exception.ArtifactStoreException;
19+
import org.eclipse.hawkbit.artifact.exception.HashNotMatchException;
20+
import org.eclipse.hawkbit.artifact.model.ArtifactHashes;
21+
import org.eclipse.hawkbit.artifact.model.StoredArtifactInfo;
1622

1723
/**
18-
* ArtifactRepository service interface.
24+
* Artifact Store service interface.
1925
*/
20-
public interface ArtifactRepository {
26+
public interface ArtifactStorage {
2127

2228
/**
2329
* Stores an artifact into the repository.
@@ -32,19 +38,20 @@ public interface ArtifactRepository {
3238
* @throws ArtifactStoreException in case storing of the artifact was not successful
3339
* @throws HashNotMatchException in case {@code hash} is provided and not matching to the calculated hashes during storing
3440
*/
35-
AbstractDbArtifact store(
41+
StoredArtifactInfo store(
3642
@NotEmpty String tenant, @NotNull InputStream content, @NotEmpty String filename,
37-
String contentType, DbArtifactHash hash);
43+
String contentType, ArtifactHashes hash);
3844

3945
/**
40-
* Retrieves a {@link AbstractDbArtifact} from the store by its SHA1 hash. Throws {@link ArtifactBinaryNotFoundException} if not found.
46+
* Retrieves a {@link StoredArtifactInfo} from the store by its SHA1 hash. Throws {@link ArtifactBinaryNotFoundException} if not found.
47+
* The caller is responsible to close the InputStream.
4148
*
4249
* @param tenant the tenant to store the artifact
4350
* @param sha1Hash the sha1-hash of the file to lookup.
4451
* @return The artifact file object or {@code null} if no file exists.
4552
* @throws UnsupportedOperationException if implementation does not support the operation
4653
*/
47-
AbstractDbArtifact getBySha1(@NotEmpty String tenant, @NotEmpty String sha1Hash);
54+
InputStream getBySha1(@NotEmpty String tenant, @NotEmpty String sha1Hash);
4855

4956
/**
5057
* Checks if an artifact exists for a given tenant by its sha1 hash
Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
/**
2-
* Copyright (c) 2025 Bosch Digital GmbH, Germany. All rights reserved.
2+
* Copyright (c) 2025 Contributors to the Eclipse Foundation
3+
*
4+
* This program and the accompanying materials are made
5+
* available under the terms of the Eclipse Public License 2.0
6+
* which is available at https://www.eclipse.org/legal/epl-2.0/
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
39
*/
4-
package org.eclipse.hawkbit.repository.artifact.encryption;
10+
package org.eclipse.hawkbit.artifact.encryption;
511

612
import java.io.InputStream;
713
import java.util.Map;
814
import java.util.Set;
915

10-
import org.eclipse.hawkbit.repository.artifact.exception.ArtifactEncryptionFailedException;
16+
import org.eclipse.hawkbit.artifact.exception.ArtifactEncryptionFailedException;
1117

1218
/**
1319
* Interface definition for artifact encryption.
@@ -55,4 +61,4 @@ public interface ArtifactEncryption {
5561
* @return encryption overhead in byte
5662
*/
5763
int encryptionSizeOverhead();
58-
}
64+
}
Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
/**
2-
* Copyright (c) 2025 Bosch Digital GmbH, Germany. All rights reserved.
2+
* Copyright (c) 2025 Contributors to the Eclipse Foundation
3+
*
4+
* This program and the accompanying materials are made
5+
* available under the terms of the Eclipse Public License 2.0
6+
* which is available at https://www.eclipse.org/legal/epl-2.0/
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
39
*/
4-
package org.eclipse.hawkbit.repository.artifact.encryption;
10+
package org.eclipse.hawkbit.artifact.encryption;
511

612
import java.util.Optional;
713

814
/**
915
* Interface definition for artifact encryption secrets store. It maintains secret key/value pairs
1016
* identified by id (e.g. software module id)
1117
*/
12-
public interface ArtifactEncryptionSecretsStore {
18+
public interface ArtifactEncryptionSecretsStorage {
1319

1420
/**
1521
* Adds secret key/value pair associated with particular id (e.g. software module id) to the store.

0 commit comments

Comments
 (0)