Skip to content

Commit c3fceda

Browse files
Merge branch 'master' into remove-remote-logger
2 parents 1cc1ee3 + 93569ae commit c3fceda

File tree

5 files changed

+186
-67
lines changed

5 files changed

+186
-67
lines changed

RELEASE-NOTES.txt

+45-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,53 @@
11
EdgeX Foundry Go Device SDK
2-
Version 1.2.3
2+
Version 1.4.0
33
Release Notes
44

55
INTRODUCTION
66
============
7-
This document contains the release notes for the 1.2.3 version of EdgeX Foundry Go Device SDK.
7+
This document contains the release notes for the 1.4.0 version of EdgeX Foundry Go Device SDK.
8+
9+
Changes for 1.4.0 "Hanoi":
10+
o PR#652: feat: add v1 deviceService callback handler
11+
o PR#678: ci: add semantic.yml for commit linting, update PR template to latest
12+
o PR#687: fix: use pointer on Executor to correctly update it
13+
o PR#686: feat: Make the numeric value type allows overflow and NaN
14+
o PR#661: feat: autoevent adds buffer for sending event to coredata
15+
o PR#650: feat(sdk): Implement Device AutoEvents SDK APIs
16+
o PR#702: feat: update DS in metadata to reflect config change
17+
18+
Changes for 1.3.0 "Hanoi":
19+
============
20+
o PR#559: Change document path from api/oas3.0/ to openapi/
21+
o PR#562: fix: allow startup duration/interval to be overridden via env vars
22+
o PR#565: fix: pass ctx into client initialization function
23+
o PR#563: fix: update CommandExists to only check Device Commands
24+
o PR#567: refactor service and clients package
25+
o PR#568: refactor handler/controller and their dependencied packages
26+
o PR#575: refactor: update dockerfile to appropriately use ENTRYPOINT and CMD
27+
o PR#576: docs: addition of version and LTS refs to README per arch's meeting
28+
o PR#579: build: add dependabot.yml
29+
o PR#588: build: upgrade to use Go 1.15
30+
o PR#570: Update Makefile and clean attribution file
31+
o PR#553: fix: Create a buffer to handle the AsyncValues
32+
o PR#592: fix: fix device autodiscovery behavior
33+
o PR#594: Update V2 swagger file to consist with edgex-go
34+
o PR#593: fix: fix autoevent panic during callback
35+
o PR#571: Remove globalvars and refactor remaining packages
36+
o PR#602: feat: implement Device SDK v2 common API
37+
o PR#612: refactor: Simplify controller signatures
38+
o PR#595: Update V2 Swagger file callback API status code
39+
o PR#617: Add Publish Swagger Parameters to Jenkinsfile
40+
o PR#615: fix: improve device discovery flow and whitelist logic
41+
o PR#603: feat: implement v2 discovery API
42+
o PR#624: refactor(sdk): release lock after discovery complete
43+
o PR#622: feat(sdk): expose RegistryClient
44+
o PR#625: feat(sdk): prepare v2 cache for v2 callback api
45+
o PR#619: feat: implement v2 command API
46+
o PR#605: feat: implement v2 callback api
47+
o PR#628: feat(sdk): start auto-discovery upon service startup
48+
o PR#641: refactor: update LogLevel for pushing event to coredata
49+
o PR#635: fix(sdk): prevent creating duplicate autoevent executor
50+
o PR#637: test/docs(sdk): update README and add unit tests
851

952
Changes for 1.2.3 "Geneva":
1053
============

internal/autoevent/manager.go

+10-4
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ type manager struct {
3131
wg *sync.WaitGroup
3232
mutex sync.Mutex
3333
autoeventBuffer chan bool
34+
dic *di.Container
3435
}
3536

3637
var (
@@ -39,12 +40,13 @@ var (
3940
)
4041

4142
// NewManager initiates the AutoEvent manager once
42-
func NewManager(ctx context.Context, wg *sync.WaitGroup, bufferSize int) {
43+
func NewManager(ctx context.Context, wg *sync.WaitGroup, bufferSize int, dic *di.Container) {
4344
m = &manager{
4445
ctx: ctx,
4546
wg: wg,
4647
executorMap: make(map[string][]*Executor),
47-
autoeventBuffer: make(chan bool, bufferSize)}
48+
autoeventBuffer: make(chan bool, bufferSize),
49+
dic: dic}
4850
}
4951

5052
func (m *manager) StartAutoEvents(dic *di.Container) bool {
@@ -94,7 +96,11 @@ func (m *manager) triggerExecutors(deviceName string, autoEvents []contract.Auto
9496

9597
// RestartForDevice restarts all the AutoEvents of the specific Device
9698
func (m *manager) RestartForDevice(deviceName string, dic *di.Container) {
97-
lc := bootstrapContainer.LoggingClientFrom(dic.Get)
99+
dc := dic
100+
if dc == nil {
101+
dc = m.dic
102+
}
103+
lc := bootstrapContainer.LoggingClientFrom(dc.Get)
98104

99105
m.StopForDevice(deviceName)
100106
d, ok := cache.Devices().ForName(deviceName)
@@ -104,7 +110,7 @@ func (m *manager) RestartForDevice(deviceName string, dic *di.Container) {
104110

105111
m.mutex.Lock()
106112
defer m.mutex.Unlock()
107-
executors := m.triggerExecutors(deviceName, d.AutoEvents, dic)
113+
executors := m.triggerExecutors(deviceName, d.AutoEvents, dc)
108114
m.executorMap[deviceName] = executors
109115
}
110116

pkg/service/init.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func NewBootstrap(router *mux.Router) *Bootstrap {
3838

3939
func (b *Bootstrap) BootstrapHandler(ctx context.Context, wg *sync.WaitGroup, startupTimer startup.Timer, dic *di.Container) (success bool) {
4040
ds.UpdateFromContainer(b.router, dic)
41-
autoevent.NewManager(ctx, wg, ds.config.Service.AsyncBufferSize)
41+
autoevent.NewManager(ctx, wg, ds.config.Service.AsyncBufferSize, dic)
4242

4343
err := ds.selfRegister()
4444
if err != nil {

pkg/service/managedautoevents.go

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// -*- Mode: Go; indent-tabs-mode: t -*-
2+
//
3+
// Copyright (C) 2020 VMware
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
7+
package service
8+
9+
import (
10+
"fmt"
11+
12+
"github.com/edgexfoundry/device-sdk-go/internal/autoevent"
13+
"github.com/edgexfoundry/device-sdk-go/internal/cache"
14+
contract "github.com/edgexfoundry/go-mod-core-contracts/models"
15+
)
16+
17+
// AddDeviceAutoEvent adds a new AutoEvent to the Device with given name
18+
func (s *DeviceService) AddDeviceAutoEvent(deviceName string, event contract.AutoEvent) error {
19+
found := false
20+
device, ok := cache.Devices().ForName(deviceName)
21+
if !ok {
22+
msg := fmt.Sprintf("Device %s cannot be found in cache", deviceName)
23+
s.LoggingClient.Error(msg)
24+
return fmt.Errorf(msg)
25+
}
26+
27+
for _, e := range device.AutoEvents {
28+
if e.Resource == event.Resource {
29+
s.LoggingClient.Debug(fmt.Sprintf("Updating existing auto event %s for device %s\n", e.Resource, deviceName))
30+
e.Frequency = event.Frequency
31+
e.OnChange = event.OnChange
32+
found = true
33+
break
34+
}
35+
}
36+
37+
if !found {
38+
s.LoggingClient.Debug(fmt.Sprintf("Adding new auto event to device %s: %v\n", deviceName, event))
39+
device.AutoEvents = append(device.AutoEvents, event)
40+
cache.Devices().Update(device)
41+
}
42+
43+
autoevent.GetManager().RestartForDevice(deviceName, nil)
44+
45+
return nil
46+
}
47+
48+
// RemoveDeviceAutoEvent removes an AutoEvent from the Device with given name
49+
func (s *DeviceService) RemoveDeviceAutoEvent(deviceName string, event contract.AutoEvent) error {
50+
device, ok := cache.Devices().ForName(deviceName)
51+
if !ok {
52+
msg := fmt.Sprintf("Device %s cannot be found in cache", deviceName)
53+
s.LoggingClient.Error(msg)
54+
return fmt.Errorf(msg)
55+
}
56+
57+
autoevent.GetManager().StopForDevice(deviceName)
58+
for i, e := range device.AutoEvents {
59+
if e.Resource == event.Resource {
60+
s.LoggingClient.Debug(fmt.Sprintf("Removing auto event %s for device %s\n", e.Resource, deviceName))
61+
device.AutoEvents = append(device.AutoEvents[:i], device.AutoEvents[i+1:]...)
62+
break
63+
}
64+
}
65+
cache.Devices().Update(device)
66+
autoevent.GetManager().RestartForDevice(deviceName, nil)
67+
68+
return nil
69+
}

pkg/service/service.go

+61-60
Original file line numberDiff line numberDiff line change
@@ -136,101 +136,102 @@ func (s *DeviceService) Stop(force bool) {
136136

137137
// selfRegister register device service itself onto metadata.
138138
func (s *DeviceService) selfRegister() error {
139-
s.LoggingClient.Debug("Trying to find Device Service: " + s.ServiceName)
139+
addr, err := s.createAndUpdateAddressable()
140+
if err != nil {
141+
s.LoggingClient.Error(fmt.Sprintf("createAndUpdateAddressable failed: %v", err))
142+
return err
143+
}
144+
145+
newDeviceService := contract.DeviceService{
146+
Name: s.ServiceName,
147+
Labels: s.config.Service.Labels,
148+
OperatingState: contract.Enabled,
149+
Addressable: *addr,
150+
AdminState: contract.Unlocked,
151+
}
152+
newDeviceService.Origin = time.Now().UnixNano() / int64(time.Millisecond)
140153

141154
ctx := context.WithValue(context.Background(), common.CorrelationHeader, uuid.New().String())
155+
s.LoggingClient.Debug("Trying to find DeviceService: " + s.ServiceName)
142156
ds, err := s.edgexClients.DeviceServiceClient.DeviceServiceForName(ctx, s.ServiceName)
143-
144157
if err != nil {
145158
if errsc, ok := err.(types.ErrServiceClient); ok && (errsc.StatusCode == http.StatusNotFound) {
146-
s.LoggingClient.Info(fmt.Sprintf("Device Service %s doesn't exist, creating a new one", s.ServiceName))
147-
ds, err = s.createNewDeviceService()
159+
s.LoggingClient.Info(fmt.Sprintf("DeviceService %s doesn't exist, creating a new one", s.ServiceName))
160+
id, err := s.edgexClients.DeviceServiceClient.Add(ctx, &newDeviceService)
161+
if err != nil {
162+
s.LoggingClient.Error(fmt.Sprintf("Failed to add Deviceservice %s: %v", s.ServiceName, err))
163+
return err
164+
}
165+
if err = common.VerifyIdFormat(id, "Device Service"); err != nil {
166+
return err
167+
}
168+
// NOTE - this differs from Addressable and Device Resources,
169+
// neither of which require the '.Service'prefix
170+
newDeviceService.Id = id
171+
s.LoggingClient.Debug("New DeviceService Id: " + newDeviceService.Id)
148172
} else {
149173
s.LoggingClient.Error(fmt.Sprintf("DeviceServicForName failed: %v", err))
150174
return err
151175
}
152176
} else {
153-
s.LoggingClient.Info(fmt.Sprintf("Device Service %s exists", ds.Name))
177+
s.LoggingClient.Info(fmt.Sprintf("DeviceService %s exists, updating it", ds.Name))
178+
err = s.edgexClients.DeviceServiceClient.Update(ctx, newDeviceService)
179+
if err != nil {
180+
s.LoggingClient.Error(fmt.Sprintf("Failed to update DeviceService %s: %v", newDeviceService.Name, err))
181+
// use the existed one to at least make sure config is in sync with metadata.
182+
newDeviceService = ds
183+
}
184+
newDeviceService.Id = ds.Id
154185
}
155186

156-
s.LoggingClient.Debug(fmt.Sprintf("Device Service in Core MetaData: %s", s.ServiceName))
157-
s.deviceService = ds
158-
187+
s.deviceService = newDeviceService
159188
return nil
160189
}
161190

162-
func (s *DeviceService) createNewDeviceService() (contract.DeviceService, error) {
163-
addr, err := s.makeNewAddressable()
164-
if err != nil {
165-
s.LoggingClient.Error(fmt.Sprintf("makeNewAddressable failed: %v", err))
166-
return contract.DeviceService{}, err
167-
}
168-
169-
millis := time.Now().UnixNano() / int64(time.Millisecond)
170-
ds := contract.DeviceService{
171-
Name: s.ServiceName,
172-
Labels: s.config.Service.Labels,
173-
OperatingState: contract.Enabled,
174-
Addressable: *addr,
175-
AdminState: contract.Unlocked,
176-
}
177-
ds.Origin = millis
178-
191+
// TODO: Addressable will be removed in v2.
192+
func (s *DeviceService) createAndUpdateAddressable() (*contract.Addressable, error) {
179193
ctx := context.WithValue(context.Background(), common.CorrelationHeader, uuid.New().String())
180-
id, err := s.edgexClients.DeviceServiceClient.Add(ctx, &ds)
181-
if err != nil {
182-
s.LoggingClient.Error(fmt.Sprintf("Add Deviceservice: %s; failed: %v", s.ServiceName, err))
183-
return contract.DeviceService{}, err
184-
}
185-
if err = common.VerifyIdFormat(id, "Device Service"); err != nil {
186-
return contract.DeviceService{}, err
194+
newAddr := contract.Addressable{
195+
Timestamps: contract.Timestamps{
196+
Origin: time.Now().UnixNano() / int64(time.Millisecond),
197+
},
198+
Name: s.ServiceName,
199+
HTTPMethod: http.MethodPost,
200+
Protocol: common.HttpProto,
201+
Address: s.config.Service.Host,
202+
Port: s.config.Service.Port,
203+
Path: common.APICallbackRoute,
187204
}
188205

189-
// NOTE - this differs from Addressable and Device Resources,
190-
// neither of which require the '.Service'prefix
191-
ds.Id = id
192-
s.LoggingClient.Debug("New device service Id: " + ds.Id)
193-
194-
return ds, nil
195-
}
196-
197-
func (s *DeviceService) makeNewAddressable() (*contract.Addressable, error) {
198-
// check whether there has been an existing addressable
199-
ctx := context.WithValue(context.Background(), common.CorrelationHeader, uuid.New().String())
200206
addr, err := s.edgexClients.AddressableClient.AddressableForName(ctx, s.ServiceName)
201207
if err != nil {
202208
if errsc, ok := err.(types.ErrServiceClient); ok && (errsc.StatusCode == http.StatusNotFound) {
203209
s.LoggingClient.Info(fmt.Sprintf("Addressable %s doesn't exist, creating a new one", s.ServiceName))
204-
millis := time.Now().UnixNano() / int64(time.Millisecond)
205-
addr = contract.Addressable{
206-
Timestamps: contract.Timestamps{
207-
Origin: millis,
208-
},
209-
Name: s.ServiceName,
210-
HTTPMethod: http.MethodPost,
211-
Protocol: common.HttpProto,
212-
Address: s.config.Service.Host,
213-
Port: s.config.Service.Port,
214-
Path: common.APICallbackRoute,
215-
}
216-
id, err := s.edgexClients.AddressableClient.Add(ctx, &addr)
210+
id, err := s.edgexClients.AddressableClient.Add(ctx, &newAddr)
217211
if err != nil {
218-
s.LoggingClient.Error(fmt.Sprintf("Add addressable failed %s, error: %v", addr.Name, err))
212+
s.LoggingClient.Error(fmt.Sprintf("Failed to add Addressable %s: %v", newAddr.Name, err))
219213
return nil, err
220214
}
221215
if err = common.VerifyIdFormat(id, "Addressable"); err != nil {
222216
return nil, err
223217
}
224-
addr.Id = id
218+
newAddr.Id = id
225219
} else {
226220
s.LoggingClient.Error(fmt.Sprintf("AddressableForName failed: %v", err))
227221
return nil, err
228222
}
229223
} else {
230-
s.LoggingClient.Info(fmt.Sprintf("Addressable %s exists", s.ServiceName))
224+
s.LoggingClient.Info(fmt.Sprintf("Addressable %s exists, updating it", s.ServiceName))
225+
err = s.edgexClients.AddressableClient.Update(ctx, newAddr)
226+
if err != nil {
227+
s.LoggingClient.Error(fmt.Sprintf("Failed to update Addressable %s: %v", s.ServiceName, err))
228+
// use the existed one to at least make sure config is in sync with metadata.
229+
newAddr = addr
230+
}
231+
newAddr.Id = addr.Id
231232
}
232233

233-
return &addr, nil
234+
return &newAddr, nil
234235
}
235236

236237
// RunningService returns the Service instance which is running

0 commit comments

Comments
 (0)