Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement bridge-device functionality for onboarding non-OCF compliant devices #420

Merged
merged 50 commits into from
Feb 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
8da3d70
implement OCF bridge device
jkralik Jan 12, 2024
b00e77d
Allow to set data to bridged device
jkralik Jan 15, 2024
67e3393
init device ondemand -> allow to configure setup
jkralik Jan 15, 2024
15940a8
cleanup API
jkralik Jan 15, 2024
d866587
clean-up API
jkralik Jan 16, 2024
44c2c39
cleanup service API
jkralik Jan 16, 2024
70caf32
check onDeviceUpdated==nil in deviceConstructor
jkralik Jan 16, 2024
dcd1222
drop invalid messsages
jkralik Jan 17, 2024
f20c8eb
fixup
jkralik Jan 17, 2024
73e4dcd
fixup
jkralik Jan 17, 2024
66e8f26
cleanup interfaces
jkralik Jan 17, 2024
8936ec2
add Shutdown method
jkralik Jan 19, 2024
fb2528a
fix shutdown
jkralik Jan 19, 2024
428fb87
fixup check in device for cloudmanager
jkralik Jan 19, 2024
ce83b3f
Fix issues and add tests (#421)
Danielius1922 Jan 19, 2024
6810f97
Refactor and add unit tests (#422)
Danielius1922 Jan 19, 2024
f24ca8c
fix deduplicate first notification
jkralik Jan 22, 2024
2d8f1ca
allow to discover mutliple devices on the same endpoint
jkralik Jan 23, 2024
949429d
fixup
jkralik Jan 23, 2024
1c4ae68
try to use also oic/res if the oic/d not exists
jkralik Jan 23, 2024
599185a
oic/res will be part of each device
jkralik Jan 23, 2024
5fe1ddb
ignore mcast with di that is not exists
jkralik Jan 24, 2024
bffb125
filter links by deviceID
jkralik Jan 24, 2024
95dc970
try to use same options when creates the observation
jkralik Jan 24, 2024
877fd89
Test observe resource
jkralik Jan 24, 2024
89e6640
add WithDeviceID option to more commands
jkralik Jan 24, 2024
386ed20
allow to configure client to set deviceID also to query parameter
jkralik Jan 25, 2024
f4c3258
fix tests
jkralik Jan 25, 2024
c4d1402
fixup test
jkralik Jan 25, 2024
8974793
generate also resources to the device
jkralik Jan 25, 2024
1d6cee4
allow to use multiple external ipv4 and ipv6 addresses
jkralik Jan 29, 2024
2df28d2
fix linter
jkralik Jan 29, 2024
733226f
fix tests
jkralik Jan 29, 2024
60cc12e
fix linter
jkralik Jan 29, 2024
31d9167
bridge: add onboarding and offboarding test
Danielius1922 Jan 22, 2024
9693baa
bridge: add maintenance resource
Danielius1922 Jan 22, 2024
784f7bd
ocfbridge: add signal handling
Danielius1922 Jan 24, 2024
b05476f
Add test-bridge target
Danielius1922 Jan 24, 2024
10ad7c3
bridge: add unit-tests
Danielius1922 Jan 24, 2024
f84a7cc
bridge: test device with mocked coap-gateway
Danielius1922 Jan 29, 2024
4c79c41
bridge: Use random for test service to avoid clashes
Danielius1922 Jan 30, 2024
6f8edf9
bridge: use secured TLS communication
Danielius1922 Jan 31, 2024
f117737
bridge: implement Credential Resource for CA Configuration during onb…
jkralik Jan 31, 2024
1192f66
new device can return also error
jkralik Feb 1, 2024
d6d3897
load config for crendtial resource
jkralik Feb 1, 2024
a553654
fix linter
jkralik Feb 1, 2024
9e994f5
publish bridge-device docker image
jkralik Feb 2, 2024
61868ed
include config.yaml
jkralik Feb 2, 2024
4bdb8b6
bridge: add custom logger support
Danielius1922 Feb 3, 2024
221b966
bridge: fix SonarCloud issues
Danielius1922 Feb 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .codecov.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
ignore:
- "client/app/app.go"
- "cmd/ocfclient/ocfclient.go"
- "cmd/bridge-device/*.go"
- "cmd/ocfclient/*.go"
- "**/main.go"
- "**/test/**/*.go"
- "**/*.pb.go"
- "**/*.pb.gw.go"
- "**/*_test.go"
Expand Down
6 changes: 0 additions & 6 deletions .github/workflows/build-publish-cfg.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ on:
description: Name of the container
type: string
required: true
directory:
description: Directory of service
type: string
required: true
file:
description: Dockerfile to build
type: string
Expand Down Expand Up @@ -102,7 +98,6 @@ jobs:
platforms: linux/amd64,linux/arm64
builder: ${{ steps.buildx.outputs.name }}
build-args: |
DIRECTORY=${{ inputs.directory }}
NAME=${{ inputs.name }}
COMMIT_DATE=${{ steps.build-args.outputs.commit_date }}
SHORT_COMMIT=${{ steps.build-args.outputs.short_commit }}
Expand All @@ -123,7 +118,6 @@ jobs:
platforms: linux/amd64,linux/arm64
builder: ${{ steps.buildx.outputs.name }}
build-args: |
DIRECTORY=${{ inputs.directory }}
NAME=${{ inputs.name }}
COMMIT_DATE=${{ steps.build-args.outputs.commit_date }}
SHORT_COMMIT=${{ steps.build-args.outputs.short_commit }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/build-publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ jobs:
matrix:
include:
- name: test-cloud-server
directory: test/cloud-server
file: test/cloud-server/Dockerfile
- name: bridge-device
file: cmd/bridge-device/Dockerfile
uses: ./.github/workflows/build-publish-cfg.yaml
with:
name: ${{ matrix.name }}
directory: ${{ matrix.directory }}
file: ${{ matrix.file }}

21 changes: 15 additions & 6 deletions .github/workflows/test-with-cfg.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ on:
name:
type: string
required: true
bridgetest-enabled:
type: boolean
required: false
default: false
coverage:
type: boolean
required: false
Expand All @@ -22,10 +26,10 @@ on:
type: string
required: false
default: ""
unittest-args:
type: string
unittest-enabled:
type: boolean
required: false
default: ""
default: false
jobs:
test:
runs-on: ubuntu-latest
Expand All @@ -51,11 +55,16 @@ jobs:
if: ${{ failure() }}
run: docker logs -t devsim-net-host && cat .tmp/devsim-net-host/0.log

# Run after integration tests, because they first clean-up the output directory
# Run after integration tests, because they always clean-up the output directory
- name: Run bridge tests
if: ${{ inputs.bridgetest-enabled }}
run: |
make test-bridge
- name: Run unit tests
if: ${{ inputs.coverage }}
if: ${{ inputs.unittest-enabled }}
run: |
make unit-test ${{ inputs.unittest-args }}
make unit-test
- name: Get output file name
if: ${{ inputs.coverage }}
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ jobs:
matrix:
include:
- name: cloud-server-debug
bridgetest-enabled: true
coverage: true
tag: ghcr.io/iotivity/iotivity-lite/cloud-server-debug:vnext
unittest-enabled: true
- name: cloud-server-debug-sha384
test-args: CERT_TOOL_SIGN_ALG=ECDSA-SHA384 CERT_TOOL_ELLIPTIC_CURVE=P384
coverage: true
Expand All @@ -37,9 +39,11 @@ jobs:
uses: ./.github/workflows/test-with-cfg.yml
with:
name: ${{ matrix.name }}
bridgetest-enabled: ${{ matrix.bridgetest-enabled || false }}
coverage: ${{ matrix.coverage }}
tag: ${{ matrix.tag }}
test-args: ${{ matrix.test-args }}
unittest-enabled: ${{ matrix.unittest-enabled || false }}

analysis:
name: SonarCloud and codecov analysis
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ vendor/
.vscode/
.tmp/
debug

cmd/bridge-device/bridge-device
cmd/ocfclient/ocfclient
test/bridge-device/bridge-device
8 changes: 6 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"-race",
"-v",
"-cover",
"-coverpkg=./...",
],
"go.testEnvVars": {
"ROOT_CA_CRT": "${workspaceFolder}/.tmp/pki_certs/cloudca.pem",
Expand All @@ -13,9 +14,12 @@
"MFG_KEY": "${workspaceFolder}/.tmp/pki_certs/mfgkey.pem",
"IDENTITY_CRT": "${workspaceFolder}/.tmp/pki_certs/identitycrt.pem",
"IDENTITY_KEY": "${workspaceFolder}/.tmp/pki_certs/identitykey.pem",
"COAP_CRT": "${workspaceFolder}/.tmp/pki_certs/coapcrt.pem",
"COAP_KEY": "${workspaceFolder}/.tmp/pki_certs/coapkey.pem",
"CLOUD_SID": "adebc667-1f2b-41e3-bf5c-6d6eabc68cc6",
},
"files.watcherExclude": {
"**/plgd-dev/device/v2/**": true
},
"**/plgd-dev/device/v2/**": true
},
"go.testTimeout": "600s",
}
131 changes: 117 additions & 14 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@ SHELL = /bin/bash
SERVICE_NAME = cloud-server-test
VERSION_TAG = vnext-$(shell git rev-parse --short=7 --verify HEAD)
SIMULATOR_NAME_SUFFIX ?= $(shell hostname)
USER_ID := $(shell id -u)
GROUP_ID := $(shell id -g)
TMP_PATH = $(shell pwd)/.tmp
CERT_PATH = $(TMP_PATH)/pki_certs
CLOUD_SID ?= adebc667-1f2b-41e3-bf5c-6d6eabc68cc6
DEVSIM_NET_HOST_PATH = $(shell pwd)/.tmp/devsim-net-host
CERT_TOOL_IMAGE ?= ghcr.io/plgd-dev/hub/cert-tool:vnext
# supported values: ECDSA-SHA256, ECDSA-SHA384, ECDSA-SHA512
CERT_TOOL_SIGN_ALG ?= ECDSA-SHA256
# supported values: P256, P384, P521
CERT_TOOL_ELLIPTIC_CURVE ?= P256
DEVSIM_IMAGE ?= ghcr.io/iotivity/iotivity-lite/cloud-server-discovery-resource-observable-debug:vnext
HUB_TEST_DEVICE_IMAGE = ghcr.io/plgd-dev/hub/test-cloud-server:vnext-pr1202
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: update to vnext after


default: build

Expand All @@ -28,21 +32,58 @@ build-testcontainer:

build: build-testcontainer

ROOT_CA_CRT = $(CERT_PATH)/cloudca.pem
ROOT_CA_KEY = $(CERT_PATH)/cloudcakey.pem
INTERMEDIATE_CA_CRT = $(CERT_PATH)/intermediatecacrt.pem
INTERMEDIATE_CA_KEY = $(CERT_PATH)/intermediatecakey.pem
MFG_CRT = $(CERT_PATH)/mfgcrt.pem
MFG_KEY = $(CERT_PATH)/mfgkey.pem
COAP_CRT = $(CERT_PATH)/coapcrt.pem
COAP_KEY = $(CERT_PATH)/coapkey.pem

certificates:
mkdir -p $(CERT_PATH)
chmod 0777 $(CERT_PATH)
docker pull $(CERT_TOOL_IMAGE)
docker run --rm -v $(CERT_PATH):/out $(CERT_TOOL_IMAGE) --outCert=/out/cloudca.pem --outKey=/out/cloudcakey.pem \
--cert.subject.cn="ca" --cert.signatureAlgorithm=$(CERT_TOOL_SIGN_ALG) --cert.ellipticCurve=$(CERT_TOOL_ELLIPTIC_CURVE) \
--cmd.generateRootCA
docker run --rm -v $(CERT_PATH):/out $(CERT_TOOL_IMAGE) --signerCert=/out/cloudca.pem --signerKey=/out/cloudcakey.pem \
--outCert=/out/intermediatecacrt.pem --outKey=/out/intermediatecakey.pem --cert.basicConstraints.maxPathLen=0 \
--cert.subject.cn="intermediateCA" --cert.signatureAlgorithm=$(CERT_TOOL_SIGN_ALG) \
--cert.ellipticCurve=$(CERT_TOOL_ELLIPTIC_CURVE) --cmd.generateIntermediateCA
docker run --rm -v $(CERT_PATH):/out $(CERT_TOOL_IMAGE) --signerCert=/out/intermediatecacrt.pem \
--signerKey=/out/intermediatecakey.pem --outCert=/out/mfgcrt.pem --outKey=/out/mfgkey.pem --cert.san.domain=localhost \
--cert.san.ip=127.0.0.1 --cert.subject.cn="mfg" --cert.signatureAlgorithm=$(CERT_TOOL_SIGN_ALG) \
--cert.ellipticCurve=$(CERT_TOOL_ELLIPTIC_CURVE) --cmd.generateCertificate

docker run \
--rm -v $(CERT_PATH):/out \
--user $(USER_ID):$(GROUP_ID) \
$(CERT_TOOL_IMAGE) \
--outCert=/out/cloudca.pem --outKey=/out/cloudcakey.pem \
--cert.subject.cn="ca" --cert.signatureAlgorithm=$(CERT_TOOL_SIGN_ALG) --cert.ellipticCurve=$(CERT_TOOL_ELLIPTIC_CURVE) \
--cmd.generateRootCA

docker run \
--rm -v $(CERT_PATH):/out \
--user $(USER_ID):$(GROUP_ID) \
$(CERT_TOOL_IMAGE) \
--signerCert=/out/cloudca.pem --signerKey=/out/cloudcakey.pem \
--outCert=/out/intermediatecacrt.pem --outKey=/out/intermediatecakey.pem \
--cert.basicConstraints.maxPathLen=0 --cert.subject.cn="intermediateCA" \
--cert.ellipticCurve=$(CERT_TOOL_ELLIPTIC_CURVE) --cert.signatureAlgorithm=$(CERT_TOOL_SIGN_ALG) \
--cmd.generateIntermediateCA

docker run \
--rm -v $(CERT_PATH):/out \
--user $(USER_ID):$(GROUP_ID) \
$(CERT_TOOL_IMAGE) \
--signerCert=/out/intermediatecacrt.pem --signerKey=/out/intermediatecakey.pem \
--outCert=/out/mfgcrt.pem --outKey=/out/mfgkey.pem --cert.san.domain=localhost \
--cert.san.ip=127.0.0.1 --cert.subject.cn="mfg" \
--cert.signatureAlgorithm=$(CERT_TOOL_SIGN_ALG) --cert.ellipticCurve=$(CERT_TOOL_ELLIPTIC_CURVE) \
--cmd.generateCertificate

docker run \
--rm -v $(CERT_PATH):/out \
--user $(USER_ID):$(GROUP_ID) \
${CERT_TOOL_IMAGE} \
--signerCert=/out/cloudca.pem --signerKey=/out/cloudcakey.pem \
--outCert=/out/coapcrt.pem --outKey=/out/coapkey.pem \
--cert.san.ip=127.0.0.1 --cert.san.domain=localhost \
--cert.signatureAlgorithm=$(CERT_TOOL_SIGN_ALG) --cert.ellipticCurve=$(CERT_TOOL_ELLIPTIC_CURVE) \
--cmd.generateCertificate --cert.subject.cn=uuid:$(CLOUD_SID)

sudo chown -R $(shell whoami) $(CERT_PATH)
chmod -R 0777 $(CERT_PATH)

Expand All @@ -64,8 +105,15 @@ env: clean certificates

unit-test: certificates
mkdir -p $(TMP_PATH)
go test -race -v ./schema/... -covermode=atomic -coverprofile=$(TMP_PATH)/schema.coverage.txt
ROOT_CA_CRT="$(CERT_PATH)/cloudca.pem" ROOT_CA_KEY="$(CERT_PATH)/cloudcakey.pem" go test -race -v ./pkg/... -covermode=atomic -coverprofile=$(TMP_PATH)/pkg.coverage.txt
ROOT_CA_CRT="$(ROOT_CA_CRT)" ROOT_CA_KEY="$(ROOT_CA_KEY)" \
MFG_CRT="$(MFG_CRT)" MFG_KEY="$(MFG_KEY)" \
INTERMEDIATE_CA_CRT="$(INTERMEDIATE_CA_CRT)" INTERMEDIATE_CA_KEY=$(INTERMEDIATE_CA_KEY) \
COAP_CRT="$(COAP_CRT)" COAP_KEY="$(COAP_KEY)" \
CLOUD_SID=$(CLOUD_SID) \
go test -race -parallel 1 -v ./bridge/... -coverpkg=./... -covermode=atomic -coverprofile=$(TMP_PATH)/bridge.unit.coverage.txt
go test -race -v ./schema/... -covermode=atomic -coverprofile=$(TMP_PATH)/schema.unit.coverage.txt
ROOT_CA_CRT="$(ROOT_CA_CRT)" ROOT_CA_KEY="$(ROOT_CA_KEY)" \
go test -race -v ./pkg/... -covermode=atomic -coverprofile=$(TMP_PATH)/pkg.unit.coverage.txt

test: env build-testcontainer
docker run \
Expand All @@ -75,8 +123,63 @@ test: env build-testcontainer
-v $(TMP_PATH):/tmp \
$(SERVICE_NAME):$(VERSION_TAG) -test.parallel 1 -test.v -test.coverprofile=/tmp/coverage.txt

test-bridge:
sudo rm -rf $(TMP_PATH)/data || :
mkdir -p $(TMP_PATH)/data
# pull image
docker pull $(HUB_TEST_DEVICE_IMAGE)
# prepare environment
docker run \
--rm \
--network=host \
--name hub-device-tests-environment \
--env PREPARE_ENV=true \
--env RUN=false \
--env COAP_GATEWAY_CLOUD_ID="$(CLOUD_SID)" \
-v $(TMP_PATH):/tmp \
-v $(TMP_PATH)/data:/data \
$(HUB_TEST_DEVICE_IMAGE)

# start device
rm -rf $(TMP_PATH)/bridge || :
mkdir -p $(TMP_PATH)/bridge
go build -C ./test/bridge-device -cover -o ./bridge-device
pkill -KILL bridge-device || :
CLOUD_SID=$(CLOUD_SID) CA_POOL=$(TMP_PATH)/data/certs/root_ca.crt \
CERT_FILE=$(TMP_PATH)/data/certs/external/coap-gateway.crt \
KEY_FILE=$(TMP_PATH)/data/certs/external/coap-gateway.key \
GOCOVERDIR=$(TMP_PATH)/bridge \
./test/bridge-device/bridge-device &

# run tests
docker run \
--rm \
--network=host \
--name hub-device-tests \
--env PREPARE_ENV=false \
--env RUN=true \
--env COAP_GATEWAY_CLOUD_ID="$(CLOUD_SID)" \
--env TEST_DEVICE_NAME="bridged-device-0" \
--env TEST_DEVICE_TYPE="bridged" \
--env GRPC_GATEWAY_TEST_DISABLED=1 \
--env IOTIVITY_LITE_TEST_RUN="(TestOffboard|TestOffboardWithoutSignIn|TestOffboardWithRepeat|TestRepublishAfterRefresh)$$" \
-v $(TMP_PATH):/tmp \
-v $(TMP_PATH)/data:/data \
$(HUB_TEST_DEVICE_IMAGE)

# stop device
pkill -TERM bridge-device || :
while pgrep -x bridge-device > /dev/null; do \
echo "waiting for bridge-device to exit"; \
sleep 1; \
done
go tool covdata textfmt -i=$(TMP_PATH)/bridge -o $(TMP_PATH)/bridge.coverage.txt

clean:
docker rm -f devsim-net-host || true
docker rm -f devsim-net-host || :
docker rm -f hub-device-tests-environment || :
docker rm -f hub-device-tests || :
pkill -KILL bridge-device || :
sudo rm -rf .tmp/*

.PHONY: build-testcontainer build certificates clean env test unit-test
5 changes: 5 additions & 0 deletions bridge/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# TODO

- Set RootCAs to the cloud connection
- Unit tests
- Set logger to package and propagate to package
35 changes: 35 additions & 0 deletions bridge/device/cloud/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/****************************************************************************
*
* Copyright (c) 2023 plgd.dev s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License"),
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************/

package cloud

import (
"github.com/plgd-dev/device/v2/schema/cloud"
)

type Configuration struct {
ResourceTypes []string `yaml:"-" json:"rt"`
Interfaces []string `yaml:"-" json:"if"`
Name string `yaml:"-" json:"n"`
AuthorizationProvider string `yaml:"authorizationProvider" json:"apn"`
CloudID string `yaml:"cloudID" json:"sid"`
URL string `yaml:"cloudEndpoint" json:"cis"`
LastErrorCode int `yaml:"-" json:"clec"`
ProvisioningStatus cloud.ProvisioningStatus `yaml:"-" json:"cps"`
AuthorizationCode string `yaml:"-" json:"-"`
}
Loading
Loading