Fix Guides in hawkBit Documentation. (#2826)

* Fix Guides in hawkBit Documentation.

Signed-off-by: strailov <Stanislav.Trailov@bosch.io>

* small fixes to clustering page

Signed-off-by: strailov <Stanislav.Trailov@bosch.io>

---------

Signed-off-by: strailov <Stanislav.Trailov@bosch.io>
This commit is contained in:
Stanislav Trailov
2025-11-26 11:49:50 +02:00
committed by GitHub
parent a7b851778e
commit 40e92be32b
10 changed files with 428 additions and 78 deletions

View File

@@ -6,7 +6,8 @@
- [Architecture](architecture.md)
- Guides
- [Run hawkBit](run-hawkbit.md)
- [Base Setup](base-setup.md)
- [SDK](hawkbit-sdk.md)
- [Feign Client](feign-client.md)
- [Clustering](clustering.md)

View File

@@ -1,7 +1,7 @@
# Run hawkBit
# Base hawkBit setup
In this guide we describe how to run a full featured hawkBit setup based on a production ready infrastructure.
It is based on the hawkBit example modules and update server.
In this guide we describe how to setup a full featured hawkBit based on a production ready infrastructure.
It is based on the hawkBit update server.
The update server can in fact be run stand alone. However, only with an embedded H2, no Device Management Federation API and no artifact storage.
@@ -13,23 +13,15 @@ This guide describes a target architecture that is more like one that you will e
- [hawkBit](https://github.com/eclipse-hawkbit/hawkbit/tree/master/hawkbit-monolith/hawkbit-update-server) Update Server
- [MariaDB](https://mariadb.org/) for the repository
- [RabbitMQ](https://www.rabbitmq.com/) for DMF communication
For testing and demonstration purposes we will also use:
- hawkBit [Device Simulator](https://github.com/eclipse-hawkbit/hawkbit-examples/tree/master/hawkbit-device-simulator)
- hawkBit [Management API example client](https://github.com/eclipse-hawkbit/hawkbit-examples/tree/master/hawkbit-example-mgmt-feign-client)
- [RabbitMQ](https://www.rabbitmq.com/) for DMF communication
---
### Prerequisites
- You have a working hawkBit [core build](https://github.com/eclipse-hawkbit/hawkbit).
- You have a working hawkBit [examples build](https://github.com/eclipse-hawkbit/hawkbit-examples).
- Adapt hawkBit Update Server and Device Simulator to your environment.
As mentioned you can create your own application with hawkBit inside or adapt the existing example app.
The second option will be shown here.
As mentioned you can create your own application with hawkBit inside.
---
@@ -53,7 +45,6 @@ spring.datasource.driverClassName: org.mariadb.jdbc.Driver
### Configure RabbitMQ (optional)
For update server and device simulator.
Defaults are already provided for a standard Rabbit installation. Otherwise configure the following in `application.properties` of the two services:
```properties
@@ -66,37 +57,11 @@ spring.rabbitmq.port: 5672
---
### Adapt hostname of example scenario &nbsp; [creation script](https://github.com/eclipse-hawkbit/hawkbit-examples/blob/master/hawkbit-example-mgmt-simulator/src/main/resources/application.properties)
Should only be necessary if your system does not run on `localhost` or uses a different port than the example app.
Adapt `application.properties` in this case:
```properties
hawkbit.url: localhost:8080
```
or provide the parameter on command line:
```properties
hawkbit-example-mgmt-simulator-##VERSION##.jar --hawkbit.url=YOUR_HOST:PORT
```
---
### Compile & Run
#### Compile & Run your “production ready” app
#### Compile & Run your app
See [update server](https://github.com/eclipse-hawkbit/hawkbit/tree/master/hawkbit-monolith/hawkbit-update-server)
#### Compile & Run example scenario creation script (optional)
This has to be done before the device simulator is started. hawkBit creates the mandatory tenant metadata with first login into either Management API (which is done by this client).
However, this is not done by DMF which is in fact used by the device simulator, i.e. without calling Management API first hawkBit would drop all DMF messages as the tenant is unknown.
#### Compile & Run device simulator (optional)
See [device simulator](https://github.com/eclipse-hawkbit/hawkbit-examples/tree/master/hawkbit-device-simulator)
---
Enjoy hawkBit with a real database, artifact storage and all interfaces available.

View File

@@ -7,25 +7,65 @@ concepts and how to setup your own cluster. You can find additional information
### Big picture
<p align="center">
<img src="images/overall_cluster.png" alt="Clustering Diagram" width="1100"/>
<img src="images/clustering_overview.png" alt="Clustering Diagram" width="1100"/>
</p>
---
### Events
Event communication between nodes is based on [Spring Cloud Bus](https://cloud.spring.io/spring-cloud-bus/) and [Spring Cloud Stream](http://docs.spring.io/spring-cloud-stream/docs/current/reference/htmlsingle/).
There are different binder implementations available. The hawkBit Update Server uses the **RabbitMQ binder**.
Every node gets its own queue to receive cluster events, the default payload is JSON. If an event is thrown locally at one node, it will be automatically delivered to all other available nodes via the Spring Cloud Buss topic exchange.
Event communication between nodes is based on [Spring Cloud Stream](http://docs.spring.io/spring-cloud-stream/docs/current/reference/htmlsingle/).
There are different [binder implementations](https://docs.spring.io/spring-cloud-stream/docs/current/reference/html/#_binders) available. The hawkbit Update Server uses **RabbitMQ binder**.
Every node gets its own queue to receive cluster events, the default payload is JSON.
<p align="center">
<img src="images/eventing-within-cluster.png" alt="Clustering Diagram" width="1100"/>
</p>
Via the `ServiceMatcher` you can check whether an event happened locally at one node or on a different node:
```java
serviceMatcher.isFromSelf(event)
#### Event Channel Types in Spring Cloud Stream
Remote events in hawkBit are distributed through two distinct types of channels:
##### Fanout Event Channel
- Every service instance listening to fanoutEventChannel receives a copy of every message, regardless of instance count.
- Common for events that should be processed by each consumer independently
- In-memory cache updates
- Internal state propagation
- Logging or auditing
- Not recommended for scenarios where only one consumer should process an event (see serviceEventChannel for that).
**Note**: Every instance bound to this channel will get its own copy of the message.
##### Service Event Channel
The `serviceEventChannel` is used to ensure exclusive consumption of events across service instances. Only one instance per consumer group receives and processes each message, which is critical for non-idempotent or resource-sensitive operations.
- Only one instance in a consumer group receives each message.
- Ideal for external integrations, third-party API calls, or any task that must not be duplicated.
- Load-balanced across instances within the same group.
##### Optional Protostuff for Spring cloud stream
The micro-service instances are configured to communicate via Spring Cloud Stream. Optionally, you could use [Protostuff](https://github.com/protostuff/protostuff) based message payload serialization for improved performance.
**Note:** If Protostuff is enabled it shall be enabled on all microservices!
Add/Uncomment to/in your `application.properties` :
```properties
spring.cloud.stream.default.content-type=application/binary+protostuff
```
Add to your `pom.xml` :
```xml
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-core</artifactId>
</dependency>
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-runtime</artifactId>
</dependency>
```
---

View File

@@ -38,32 +38,3 @@ public class CreateStartedRolloutExample {
}
}
```
Example projects:
- [hawkbit-example-mgmt-feign-client](https://github.com/eclipse-hawkbit/hawkbit-examples/tree/master/hawkbit-example-mgmt-feign-client)
- [hawkbit-example-ddi-feign-client](https://github.com/eclipse-hawkbit/hawkbit-examples/tree/master/hawkbit-example-ddi-feign-client)
- [hawkbit-example-mgmt-simulator](https://github.com/eclipse-hawkbit/hawkbit-examples/tree/master/hawkbit-example-mgmt-simulator)
---
### Feign Client Configuration
At [`hawkbit-example-core-feign-client`](https://github.com/eclipse-hawkbit/hawkbit-examples/tree/master/hawkbit-example-core-feign-client) there is a Spring configuration to auto configure some beans, which can be reused for your own Feign client:
```java
@Configuration
@ConditionalOnClass(Feign.class)
@Import(FeignClientsConfiguration.class)
public class FeignClientConfiguration {
@Bean
public ApplicationJsonRequestHeaderInterceptor jsonHeaderInterceptor() {
return new ApplicationJsonRequestHeaderInterceptor();
}
@Bean
public Contract feignContract() {
return new IgnoreMultipleConsumersProducersSpringMvcContract();
}
}
```

View File

@@ -0,0 +1,161 @@
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0" version="29.1.0">
<diagram name="Page-1" id="BYhKT5RE8sAJkKKtov_M">
<mxGraphModel dx="1234" dy="723" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-1" parent="1" style="verticalAlign=top;align=center;spacingTop=8;spacingLeft=2;spacingRight=12;shape=cube;size=10;direction=south;fontStyle=0;html=1;whiteSpace=wrap;fillColor=#d5e8d4;strokeColor=#82b366;" value="&lt;div align=&quot;center&quot;&gt;&amp;lt;VM&amp;gt;&lt;/div&gt;" vertex="1">
<mxGeometry height="190" width="260" x="480" y="350" as="geometry" />
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-6" parent="1" style="verticalAlign=top;align=center;spacingTop=8;spacingLeft=2;spacingRight=12;shape=cube;size=10;direction=south;fontStyle=0;html=1;whiteSpace=wrap;fillColor=#e1d5e7;strokeColor=#9673a6;" value="&lt;div align=&quot;center&quot;&gt;hawkbit&lt;/div&gt;&lt;div align=&quot;center&quot;&gt;&lt;br&gt;&lt;/div&gt;&lt;div align=&quot;center&quot;&gt;Node 1&lt;/div&gt;" vertex="1">
<mxGeometry height="85" width="130" x="545" y="402.5" as="geometry" />
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-10" parent="1" style="strokeWidth=2;html=1;shape=mxgraph.flowchart.database;whiteSpace=wrap;fillColor=#fff2cc;strokeColor=#d6b656;" value="" vertex="1">
<mxGeometry height="30" width="60" x="500" y="470" as="geometry" />
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-7" parent="1" style="strokeWidth=2;html=1;shape=mxgraph.flowchart.database;whiteSpace=wrap;fillColor=#fff2cc;strokeColor=#d6b656;" value="Caches" vertex="1">
<mxGeometry height="30" width="60" x="518" y="485" as="geometry" />
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-12" parent="1" style="verticalAlign=top;align=center;spacingTop=8;spacingLeft=2;spacingRight=12;shape=cube;size=10;direction=south;fontStyle=0;html=1;whiteSpace=wrap;fillColor=#d5e8d4;strokeColor=#82b366;" value="&lt;div align=&quot;center&quot;&gt;&amp;lt;VM&amp;gt;&lt;/div&gt;" vertex="1">
<mxGeometry height="190" width="260" x="800" y="350" as="geometry" />
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-13" parent="1" style="verticalAlign=top;align=center;spacingTop=8;spacingLeft=2;spacingRight=12;shape=cube;size=10;direction=south;fontStyle=0;html=1;whiteSpace=wrap;fillColor=#e1d5e7;strokeColor=#9673a6;" value="&lt;div align=&quot;center&quot;&gt;&lt;span&gt;hawkbit&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Node 2&lt;/span&gt;&lt;/div&gt;" vertex="1">
<mxGeometry height="85" width="130" x="865" y="402.5" as="geometry" />
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-14" parent="1" style="strokeWidth=2;html=1;shape=mxgraph.flowchart.database;whiteSpace=wrap;fillColor=#fff2cc;strokeColor=#d6b656;" value="" vertex="1">
<mxGeometry height="30" width="60" x="820" y="470" as="geometry" />
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-15" parent="1" style="strokeWidth=2;html=1;shape=mxgraph.flowchart.database;whiteSpace=wrap;fillColor=#fff2cc;strokeColor=#d6b656;" value="Caches" vertex="1">
<mxGeometry height="30" width="60" x="838" y="485" as="geometry" />
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-16" parent="1" style="verticalAlign=top;align=center;spacingTop=8;spacingLeft=2;spacingRight=12;shape=cube;size=10;direction=south;fontStyle=0;html=1;whiteSpace=wrap;fillColor=#d5e8d4;strokeColor=#82b366;" value="&amp;lt;VM&amp;gt;" vertex="1">
<mxGeometry height="190" width="260" x="1130" y="350" as="geometry" />
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-17" parent="1" style="verticalAlign=top;align=center;spacingTop=8;spacingLeft=2;spacingRight=12;shape=cube;size=10;direction=south;fontStyle=0;html=1;whiteSpace=wrap;fillColor=#e1d5e7;strokeColor=#9673a6;" value="&lt;div align=&quot;center&quot;&gt;hawkbit&lt;/div&gt;&lt;div align=&quot;center&quot;&gt;&lt;br&gt;&lt;/div&gt;&lt;div align=&quot;center&quot;&gt;Node 3&lt;/div&gt;" vertex="1">
<mxGeometry height="85" width="130" x="1195" y="402.5" as="geometry" />
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-18" parent="1" style="strokeWidth=2;html=1;shape=mxgraph.flowchart.database;whiteSpace=wrap;fillColor=#fff2cc;strokeColor=#d6b656;" value="" vertex="1">
<mxGeometry height="30" width="60" x="1150" y="470" as="geometry" />
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-19" parent="1" style="strokeWidth=2;html=1;shape=mxgraph.flowchart.database;whiteSpace=wrap;fillColor=#fff2cc;strokeColor=#d6b656;" value="Caches" vertex="1">
<mxGeometry height="30" width="60" x="1168" y="485" as="geometry" />
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-20" parent="1" style="verticalAlign=top;align=left;spacingTop=8;spacingLeft=2;spacingRight=12;shape=cube;size=10;direction=south;fontStyle=4;html=1;whiteSpace=wrap;fillColor=#d5e8d4;strokeColor=#82b366;" value="&amp;lt;VM&amp;gt;" vertex="1">
<mxGeometry height="230" width="910" x="480" y="90" as="geometry" />
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-21" parent="1" style="verticalAlign=top;align=left;spacingTop=8;spacingLeft=2;spacingRight=12;shape=cube;size=10;direction=south;fontStyle=4;html=1;whiteSpace=wrap;fillColor=light-dark(#dae8fc, #1d293b);strokeColor=#6c8ebf;" value="RabbitMQ" vertex="1">
<mxGeometry height="170" width="875" x="495" y="130" as="geometry" />
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-25" edge="1" parent="1" source="6fOQ1n0bxIv4FP22A9Zj-6" style="endArrow=none;html=1;rounded=0;exitX=0;exitY=0;exitDx=47.5;exitDy=130;exitPerimeter=0;endFill=0;" target="6fOQ1n0bxIv4FP22A9Zj-32" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<Array as="points">
<mxPoint x="460" y="450" />
<mxPoint x="460" y="185" />
</Array>
<mxPoint x="460" y="442" as="sourcePoint" />
<mxPoint x="590" y="190" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-26" parent="1" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;rotation=90;fillColor=#ffe6cc;strokeColor=#d79b00;" value="" vertex="1">
<mxGeometry height="135" width="32.75" x="918.44" y="207.32" as="geometry" />
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-27" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;dashed=1;" target="6fOQ1n0bxIv4FP22A9Zj-26" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<Array as="points">
<mxPoint x="933" y="240" />
<mxPoint x="1030" y="240" />
<mxPoint x="1030" y="275" />
</Array>
<mxPoint x="932.5" y="205" as="sourcePoint" />
<mxPoint x="970" y="350" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-28" edge="1" parent="1" source="6fOQ1n0bxIv4FP22A9Zj-26" style="endArrow=classic;html=1;rounded=0;dashed=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0;entryDx=47.5;entryDy=130;entryPerimeter=0;" target="6fOQ1n0bxIv4FP22A9Zj-13" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<Array as="points">
<mxPoint x="830" y="275" />
<mxPoint x="830" y="450" />
</Array>
<mxPoint x="790" y="320" as="sourcePoint" />
<mxPoint x="770" y="350" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-29" parent="1" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;rotation=90;fillColor=#ffe6cc;strokeColor=#d79b00;" value="" vertex="1">
<mxGeometry height="130" width="32.75" x="1248.44" y="209.82" as="geometry" />
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-30" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;dashed=1;" target="6fOQ1n0bxIv4FP22A9Zj-29" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<Array as="points">
<mxPoint x="1350" y="185" />
<mxPoint x="1350" y="275" />
</Array>
<mxPoint x="952.5" y="185" as="sourcePoint" />
<mxPoint x="910" y="370" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-31" edge="1" parent="1" source="6fOQ1n0bxIv4FP22A9Zj-29" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0;entryDx=47.5;entryDy=130;entryPerimeter=0;dashed=1;" target="6fOQ1n0bxIv4FP22A9Zj-17" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<Array as="points">
<mxPoint x="1160" y="275" />
<mxPoint x="1160" y="450" />
</Array>
<mxPoint x="860" y="420" as="sourcePoint" />
<mxPoint x="910" y="370" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-32" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="&lt;div&gt;request&lt;/div&gt;" vertex="1">
<mxGeometry height="30" width="60" x="640" y="170" as="geometry" />
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-33" edge="1" parent="1" source="6fOQ1n0bxIv4FP22A9Zj-32" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<mxPoint x="710" y="185" as="sourcePoint" />
<mxPoint x="912.5" y="185" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-34" parent="1" style="strokeWidth=2;html=1;shape=mxgraph.flowchart.database;whiteSpace=wrap;fillColor=#fff2cc;strokeColor=#d6b656;" value="Storage" vertex="1">
<mxGeometry height="80" width="160" x="846" y="660" as="geometry" />
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-35" edge="1" parent="1" source="6fOQ1n0bxIv4FP22A9Zj-1" style="endArrow=none;html=1;rounded=0;exitX=0;exitY=0;exitDx=190;exitDy=135;exitPerimeter=0;entryX=0;entryY=0;entryDx=190;entryDy=135;entryPerimeter=0;" target="6fOQ1n0bxIv4FP22A9Zj-16" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<Array as="points">
<mxPoint x="605" y="600" />
<mxPoint x="1255" y="600" />
</Array>
<mxPoint x="860" y="520" as="sourcePoint" />
<mxPoint x="910" y="470" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-37" edge="1" parent="1" source="6fOQ1n0bxIv4FP22A9Zj-12" style="endArrow=classic;html=1;rounded=0;exitX=0;exitY=0;exitDx=190;exitDy=135;exitPerimeter=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;" target="6fOQ1n0bxIv4FP22A9Zj-34" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<mxPoint x="860" y="520" as="sourcePoint" />
<mxPoint x="910" y="470" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-38" parent="1" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" value="&lt;div&gt;User&lt;/div&gt;" vertex="1">
<mxGeometry height="60" width="30" x="480" y="630" as="geometry" />
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-41" edge="1" parent="1" source="6fOQ1n0bxIv4FP22A9Zj-42" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=0;entryDx=85;entryDy=70;entryPerimeter=0;exitX=0.5;exitY=0;exitDx=0;exitDy=0;" target="6fOQ1n0bxIv4FP22A9Zj-6" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<mxPoint x="550" y="570" as="sourcePoint" />
<mxPoint x="1020" y="460" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-42" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="user action" vertex="1">
<mxGeometry height="30" width="90" x="494" y="570" as="geometry" />
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-44" edge="1" parent="1" style="endArrow=none;html=1;rounded=0;entryX=0.25;entryY=1;entryDx=0;entryDy=0;" target="6fOQ1n0bxIv4FP22A9Zj-42" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<mxPoint x="500" y="620" as="sourcePoint" />
<mxPoint x="1020" y="460" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-45" parent="1" style="shape=sumEllipse;perimeter=ellipsePerimeter;whiteSpace=wrap;html=1;backgroundOutline=1;strokeWidth=2;fillColor=#DAE8FC;" value="" vertex="1">
<mxGeometry height="40" width="40" x="912.5" y="164.82" as="geometry" />
</mxCell>
<mxCell id="6fOQ1n0bxIv4FP22A9Zj-46" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="&amp;lt;exchange&amp;gt;" vertex="1">
<mxGeometry height="30" width="60" x="902.82" y="136.82" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

View File

@@ -0,0 +1,104 @@
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0" version="29.1.0">
<diagram name="Page-1" id="8TI6eQ3P8_G0a2ucj6mY">
<mxGraphModel dx="1234" dy="723" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="En0P6fcSIc41xqj2JpCt-3" parent="1" style="html=1;shape=mxgraph.sysml.package;html=1;overflow=fill;whiteSpace=wrap;fillColor=#e1d5e7;strokeColor=light-dark(#9673a6, #9577a3);" value="&lt;p style=&quot;margin:0px;margin-top:4px;margin-left:10px;text-align:left;&quot;&gt;&lt;b&gt;Node 1&lt;/b&gt;&lt;/p&gt;" vertex="1">
<mxGeometry height="280" width="460" x="160" y="260" as="geometry" />
</mxCell>
<mxCell id="En0P6fcSIc41xqj2JpCt-4" parent="1" style="shape=module;align=left;spacingLeft=20;align=center;verticalAlign=top;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontColor=#333333;" value="spring-context" vertex="1">
<mxGeometry height="50" width="120" x="190" y="310" as="geometry" />
</mxCell>
<mxCell id="En0P6fcSIc41xqj2JpCt-6" parent="1" style="shape=module;align=left;spacingLeft=20;align=center;verticalAlign=top;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontColor=#333333;" value="Repository" vertex="1">
<mxGeometry height="50" width="120" x="190" y="455" as="geometry" />
</mxCell>
<mxCell id="En0P6fcSIc41xqj2JpCt-8" parent="1" style="shape=module;align=left;spacingLeft=20;align=center;verticalAlign=top;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontColor=#333333;" value="spring-cloud-stream" vertex="1">
<mxGeometry height="50" width="120" x="450" y="310" as="geometry" />
</mxCell>
<mxCell id="En0P6fcSIc41xqj2JpCt-10" parent="1" style="html=1;shape=mxgraph.sysml.package;html=1;overflow=fill;whiteSpace=wrap;fillColor=#e1d5e7;strokeColor=#9673a6;" value="&lt;p style=&quot;margin:0px;margin-top:4px;margin-left:10px;text-align:left;&quot;&gt;&lt;b&gt;Node 2&lt;/b&gt;&lt;/p&gt;" vertex="1">
<mxGeometry height="280" width="460" x="860" y="260" as="geometry" />
</mxCell>
<mxCell id="En0P6fcSIc41xqj2JpCt-11" parent="1" style="shape=module;align=left;spacingLeft=20;align=center;verticalAlign=top;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontColor=#333333;" value="spring-cloud-stream" vertex="1">
<mxGeometry height="50" width="120" x="900" y="310" as="geometry" />
</mxCell>
<mxCell id="En0P6fcSIc41xqj2JpCt-12" parent="1" style="shape=module;align=left;spacingLeft=20;align=center;verticalAlign=top;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontColor=#333333;" value="spring-context" vertex="1">
<mxGeometry height="50" width="120" x="1155" y="310" as="geometry" />
</mxCell>
<mxCell id="En0P6fcSIc41xqj2JpCt-13" parent="1" style="shape=module;align=left;spacingLeft=20;align=center;verticalAlign=top;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontColor=#333333;" value="Local Listeners" vertex="1">
<mxGeometry height="50" width="120" x="1155" y="455" as="geometry" />
</mxCell>
<mxCell id="En0P6fcSIc41xqj2JpCt-18" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.05;entryY=0.52;entryDx=0;entryDy=0;entryPerimeter=0;" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<mxPoint x="310" y="334.5" as="sourcePoint" />
<mxPoint x="460" y="334.5" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="En0P6fcSIc41xqj2JpCt-23" edge="1" parent="1" source="En0P6fcSIc41xqj2JpCt-6" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" target="En0P6fcSIc41xqj2JpCt-4" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<mxPoint x="250" y="399" as="sourcePoint" />
<mxPoint x="370" y="375" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="En0P6fcSIc41xqj2JpCt-35" connectable="0" parent="En0P6fcSIc41xqj2JpCt-23" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=#E1D5E7;" value="publish" vertex="1">
<mxGeometry relative="1" x="-0.1158" y="-3" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="En0P6fcSIc41xqj2JpCt-25" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="notify" vertex="1">
<mxGeometry height="30" width="60" x="350" y="300" as="geometry" />
</mxCell>
<mxCell id="En0P6fcSIc41xqj2JpCt-26" parent="1" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;direction=south;fillColor=#ffe6cc;strokeColor=#d79b00;" value="" vertex="1">
<mxGeometry height="60" width="140" x="750" y="110" as="geometry" />
</mxCell>
<mxCell id="En0P6fcSIc41xqj2JpCt-27" parent="1" style="verticalLabelPosition=bottom;verticalAlign=top;html=1;shape=mxgraph.flowchart.or;strokeWidth=2;" value="" vertex="1">
<mxGeometry height="30" width="30" x="620" y="125" as="geometry" />
</mxCell>
<mxCell id="En0P6fcSIc41xqj2JpCt-28" edge="1" parent="1" source="En0P6fcSIc41xqj2JpCt-8" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" target="En0P6fcSIc41xqj2JpCt-27" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<Array as="points">
<mxPoint x="510" y="140" />
</Array>
<mxPoint x="730" y="400" as="sourcePoint" />
<mxPoint x="780" y="350" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="En0P6fcSIc41xqj2JpCt-29" edge="1" parent="1" source="En0P6fcSIc41xqj2JpCt-27" style="endArrow=classic;html=1;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;entryPerimeter=0;" target="En0P6fcSIc41xqj2JpCt-26" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<mxPoint x="730" y="400" as="sourcePoint" />
<mxPoint x="780" y="350" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="En0P6fcSIc41xqj2JpCt-30" edge="1" parent="1" source="En0P6fcSIc41xqj2JpCt-26" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="En0P6fcSIc41xqj2JpCt-11" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<Array as="points">
<mxPoint x="960" y="140" />
</Array>
<mxPoint x="730" y="400" as="sourcePoint" />
<mxPoint x="780" y="350" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="En0P6fcSIc41xqj2JpCt-31" edge="1" parent="1" source="En0P6fcSIc41xqj2JpCt-11" style="endArrow=classic;html=1;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<mxPoint x="1025" y="335" as="sourcePoint" />
<mxPoint x="1165" y="335" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="En0P6fcSIc41xqj2JpCt-32" edge="1" parent="1" source="En0P6fcSIc41xqj2JpCt-12" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="En0P6fcSIc41xqj2JpCt-13" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<mxPoint x="730" y="400" as="sourcePoint" />
<mxPoint x="780" y="350" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="En0P6fcSIc41xqj2JpCt-34" connectable="0" parent="En0P6fcSIc41xqj2JpCt-32" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];textShadow=0;labelBackgroundColor=light-dark(#E1D5E7,#EDEDED);" value="notify" vertex="1">
<mxGeometry relative="1" x="-0.0316" y="3" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="En0P6fcSIc41xqj2JpCt-33" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="publish" vertex="1">
<mxGeometry height="30" width="60" x="1060" y="300" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

108
docs/hawkbit-sdk.md Normal file
View File

@@ -0,0 +1,108 @@
# hawkBit SDK
In this guide we describe what is hawkBit SDK, how can it be configured and used.
---
### Overview
hawkBit provides a Client-Side Software Development Kit which allows you to:
- Connect a device or a Gateway to hawkBit
- Fetch assignments / update campaigns
- Download firmware or software packages
- Report progress and status
- Interact with Management, DDI, and DMF APIs through one client
[hawkBit SDK](https://github.com/eclipse-hawkbit/hawkbit/tree/master/hawkbit-sdk) has support for DDI, DMF and Mgmt APIs. In other words it allows you to simulate (only simulate?) the behaviour of a DDI/DMF gateway/target or interact with hawkBit through MgmtAPI.
---
### Configuration
Add the desired modules :
```xml
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-sdk-device</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-sdk-dmf</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-sdk-mgmt</artifactId>
</dependency>
```
Of course if you will not be using DMF there is no need to add `hawkbit-sdk-dmf` or vise versa for DDI case.
The default configuration comes already built-in with the SDK.
But it can be changed in ```application.properties``` of your service/application:
```properties
hawkbit.tenant.tenant-id=DEFAULT
hawkbit.tenant.username=user
hawkbit.tenant.password=pass
hawkbit.tenant.gateway-token=gateway_token
# DMF case
hawkbit.tenant.dmf.username=dmf_user
hawkbit.tenant.dmf.password=dmf_password
hawkbit.tenant.dmf.virtual-host=dmf_vhost
```
And also you can configure the endpoints of HawkBit and DDI (if used separately as microservices) :
```properties
# Hawkbit Server config
hawkbit.server.mgmt-url=http://localhost:8080
hawkbit.server.ddi-url=http://localhost:8085
```
Many other configuration options are possible, you can check [HawkbitServer](https://github.com/eclipse-hawkbit/hawkbit/blob/master/hawkbit-sdk/hawkbit-sdk-commons/src/main/java/org/eclipse/hawkbit/sdk/HawkbitServer.java) and [Tenant](https://github.com/eclipse-hawkbit/hawkbit/blob/master/hawkbit-sdk/hawkbit-sdk-commons/src/main/java/org/eclipse/hawkbit/sdk/Tenant.java) classes for more possible configuration properties.
---
### Example applications
If you have applied the configurations from the steps above then you can start building your application. Since we have defined `hawkbit.server` and `hawkbit.tenant` properties then you can add the `HawkbitClient` bean into your application :
```java
@Bean
HawkbitClient hawkbitClient(final HawkbitServer hawkBitServer, final Encoder encoder, final Decoder decoder, final Contract contract) {
return new HawkbitClient(hawkBitServer, encoder, decoder, contract);
}
```
Then you can define the authentication setup helper, which offers helper methods for setting up your authentication method(s) :
```java
@Bean
AuthenticationSetupHelper mgmtApi(final Tenant tenant, final HawkbitClient hawkbitClient) {
return new AuthenticationSetupHelper(tenant, hawkbitClient);
}
```
And finally you can define a Bean instance of `DdiTenant` which offers you interaction with DDI API :
```java
@Bean
DdiTenant ddiTenant(final Tenant defaultTenant, final HawkbitClient hawkbitClient) {
return new DdiTenant(defaultTenant, hawkbitClient);
}
```
Hawkbit Mgmt API can be now also reached via `HawkbitClient` instance :
```java
final MgmtTargetRestApi mgmtTargetRestApi = hawkbitClient.mgmtService(MgmtTargetRestApi.class, tenant);
// directly use MGMT REST API methods
PagedList<MgmtTarget> pagedList = mgmtTargetRestApi.getTargets("controllerid==*",0, 100,
null).getBody();
```
You can check out the example applications located in [hawkbit-sdk-demo](https://github.com/eclipse-hawkbit/hawkbit/tree/master/hawkbit-sdk/hawkbit-sdk-demo) module.
There you can find example usage for [DDI](https://github.com/eclipse-hawkbit/hawkbit/blob/master/hawkbit-sdk/hawkbit-sdk-demo/src/main/java/org/eclipse/hawkbit/sdk/demo/device/DeviceApp.java) and [DMF](https://github.com/eclipse-hawkbit/hawkbit/blob/master/hawkbit-sdk/hawkbit-sdk-demo/src/main/java/org/eclipse/hawkbit/sdk/demo/dmf/DmfApp.java) via the hawkbit SDK.

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB