Skip to content

Commit aceebb9

Browse files
authored
[#31] Consider setting progress when operation status is changed to DOWNLOADING or INSTALLING/INSTALLED (#77)
[#31] Consider setting progress when operation status is changed to DOWNLOADING or INSTALLING/INSTALLED Signed-off-by: Mahesha Mutharayappa (SDS/EPE2) <[email protected]>
1 parent 74b2b45 commit aceebb9

12 files changed

+112
-40
lines changed

hawkbit/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,10 @@ if err := su.SetContextDependencies(dependency); err != nil {
9393
```go
9494
func installHandler(update *hawkbit.SoftwareUpdateAction, su *hawkbit.SoftwareUpdatable) {
9595
// Install provided software modules.
96+
startProgress := 0
9697
for _, module := range update.SoftwareModules {
9798
status := hawkbit.NewOperationStatusUpdate(update.CorrelationID, hawkbit.StatusStarted, module.SoftwareModule).
98-
WithProgress(0).WithMessage("install operation just started")
99+
WithProgress(&startProgress).WithMessage("install operation just started")
99100
if err := su.SetLastOperation(status); err != nil {
100101
fmt.Println(fmt.Errorf("could not update the last operation: %v", err))
101102
}

hawkbit/lib_dependency_description.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@
1212

1313
package hawkbit
1414

15+
// Software DependencyDescription structure keys
16+
const (
17+
softwareGroupParam = "group"
18+
softwareNameParam = "name"
19+
softwareVersionParam = "version"
20+
softwareTypeParam = "type"
21+
)
22+
1523
// DependencyDescription describes an installed software or other dependencies for a device.
1624
type DependencyDescription struct {
1725
// Group represents an identifier which groups the dependency into a certain category.

hawkbit/lib_operation_status.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@
1212

1313
package hawkbit
1414

15+
// OperationStatus structure keys
16+
const (
17+
correlationIDParam = "correlationID"
18+
statusParam = "status"
19+
softwareModuleParam = "softwareModule"
20+
SoftwareParam = "Software"
21+
progressParam = "progress"
22+
messageParam = "message"
23+
statusCodeParam = "statusCode"
24+
)
25+
1526
// OperationStatus represents the status of an operation (install/remove) called on a device.
1627
type OperationStatus struct {
1728
// CorrelationID is used for correlating the status-update with the operation called before.
@@ -24,7 +35,7 @@ type OperationStatus struct {
2435
// Software is required for a remove or cancelRemove operation, absent in case of install/download/cancel.
2536
Software []*DependencyDescription `json:"software,omitempty"`
2637
// Progress represents the progress indicator in percentage.
27-
Progress int `json:"progress,omitempty"`
38+
Progress *int `json:"progress,omitempty"`
2839
// Message from the device to give more context to the transmitted status.
2940
Message string `json:"message,omitempty"`
3041
// StatusCode represents a custom status code transmitted by the device.
@@ -67,7 +78,7 @@ func (os *OperationStatus) WithSoftware(software ...*DependencyDescription) *Ope
6778
}
6879

6980
// WithProgress sets the progress of the operation status.
70-
func (os *OperationStatus) WithProgress(progress int) *OperationStatus {
81+
func (os *OperationStatus) WithProgress(progress *int) *OperationStatus {
7182
os.Progress = progress
7283
return os
7384
}

hawkbit/lib_operation_status_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func TestOperationStatusUpdate(t *testing.T) {
5555
}
5656

5757
// 4. Test WithProgress value.
58-
if ops.WithProgress(progress).Progress != progress {
58+
if *(ops.WithProgress(&progress).Progress) != progress {
5959
t.Errorf("progress mishmash: %v != %v", ops.Progress, progress)
6060
}
6161

hawkbit/lib_software_module_id.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@
1212

1313
package hawkbit
1414

15+
// SoftwareModuleID structure keys
16+
const (
17+
softwareModuleNameParam = "name"
18+
softwareModuleVersionParam = "version"
19+
)
20+
1521
// SoftwareModuleID represents an unique identifier for software modules.
1622
type SoftwareModuleID struct {
1723
// Name for the software module.

hawkbit/software_updatable.go

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,49 @@ func (su *SoftwareUpdatable) SetContextDependencies(deps ...*DependencyDescripti
132132
return su.setProperty(suPropertyContextDependencies, su.status.ContextDependencies)
133133
}
134134

135+
// MapLastOperation converts the OperationStatus into map interface
136+
// This enables the logging of last operation status with keys and values
137+
func MapLastOperation(LastOperationPtr *OperationStatus) map[string]interface{} {
138+
lastOperationMap := make(map[string]interface{})
139+
lastOperationMap[correlationIDParam] = LastOperationPtr.CorrelationID
140+
lastOperationMap[statusParam] = LastOperationPtr.Status
141+
142+
if LastOperationPtr.SoftwareModule != nil {
143+
lastOperationMap[softwareModuleParam] = map[string]interface{}{
144+
softwareModuleNameParam: LastOperationPtr.SoftwareModule.Name,
145+
softwareModuleVersionParam: LastOperationPtr.SoftwareModule.Version,
146+
}
147+
}
148+
149+
if LastOperationPtr.Software != nil {
150+
var softwareDependencies []map[string]interface{}
151+
for _, values := range LastOperationPtr.Software {
152+
dependency := map[string]interface{}{
153+
softwareGroupParam: values.Group,
154+
softwareNameParam: values.Name,
155+
softwareVersionParam: values.Version,
156+
softwareTypeParam: values.Type,
157+
}
158+
softwareDependencies = append(softwareDependencies, dependency)
159+
}
160+
lastOperationMap[SoftwareParam] = softwareDependencies
161+
}
162+
163+
if LastOperationPtr.Progress != nil {
164+
lastOperationMap[progressParam] = *LastOperationPtr.Progress
165+
}
166+
167+
if LastOperationPtr.Message != "" {
168+
lastOperationMap[messageParam] = LastOperationPtr.Message
169+
}
170+
171+
if LastOperationPtr.StatusCode != "" {
172+
lastOperationMap[statusCodeParam] = LastOperationPtr.StatusCode
173+
}
174+
175+
return lastOperationMap
176+
}
177+
135178
// SetLastOperation set the last operation and last failed operation (if needed) of
136179
// underlying SoftwareUpdatable feature.
137180
// Note: Involking this function before the feature activation will change
@@ -146,9 +189,9 @@ func (su *SoftwareUpdatable) SetLastOperation(os *OperationStatus) error {
146189
if os != nil && (os.Status == StatusFinishedError || os.Status == StatusFinishedRejected ||
147190
os.Status == StatusCancelRejected) {
148191
su.status.LastFailedOperation = su.status.LastOperation
149-
if err := su.setProperty(suPropertyLastFailedOperation, su.status.LastFailedOperation); err != nil {
192+
if err := su.setProperty(suPropertyLastFailedOperation, MapLastOperation(su.status.LastFailedOperation)); err != nil {
150193
return err
151194
}
152195
}
153-
return su.setProperty(suPropertyLastOperation, su.status.LastOperation)
196+
return su.setProperty(suPropertyLastOperation, MapLastOperation(su.status.LastOperation))
154197
}

internal/feature_download.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ func (f *ScriptBasedSoftwareUpdatable) downloadModule(
7676
s := filepath.Join(toDir, storage.InternalStatusName)
7777
var opError error
7878
opErrorMsg := errRuntime
79+
startProgress := 0
80+
completeProgress := 100
7981

8082
// Process final operation status in defer to also catch potential panic calls.
8183
defer func() {
@@ -119,11 +121,11 @@ Started:
119121

120122
// Downloading
121123
logger.Debugf("[%s.%s] Downloading module", module.Name, module.Version)
122-
setLastOS(su, newOS(cid, module, hawkbit.StatusDownloading))
124+
setLastOS(su, newOS(cid, module, hawkbit.StatusDownloading).WithProgress(&startProgress))
123125
storage.WriteLn(s, string(hawkbit.StatusDownloading))
124126
Downloading:
125-
if opError = f.store.DownloadModule(toDir, module, func(percent int) {
126-
setLastOS(su, newOS(cid, module, hawkbit.StatusDownloading).WithProgress(percent))
127+
if opError = f.store.DownloadModule(toDir, module, func(progress int) {
128+
setLastOS(su, newOS(cid, module, hawkbit.StatusDownloading).WithProgress(&progress))
127129
}, f.serverCert, f.downloadRetryCount, f.downloadRetryInterval, func() error {
128130
return f.validateLocalArtifacts(module)
129131
}); opError != nil {
@@ -134,7 +136,7 @@ Downloading:
134136

135137
// Downloaded
136138
logger.Debugf("[%s.%s] Module download finished", module.Name, module.Version)
137-
setLastOS(su, newOS(cid, module, hawkbit.StatusDownloaded).WithProgress(100))
139+
setLastOS(su, newOS(cid, module, hawkbit.StatusDownloaded).WithProgress(&completeProgress))
138140
storage.WriteLn(s, string(hawkbit.StatusDownloaded))
139141
return false
140142
}

internal/feature_install.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ func (f *ScriptBasedSoftwareUpdatable) installModule(
7272
s := filepath.Join(dir, storage.InternalStatusName)
7373
var opError error
7474
opErrorMsg := errRuntime
75-
75+
startProgress := 0
76+
completeProgress := 100
7677
execInstallScriptDir := dir
7778

7879
// Process final operation status in defer to also catch potential panic calls.
@@ -128,11 +129,11 @@ func (f *ScriptBasedSoftwareUpdatable) installModule(
128129
Started:
129130
// Downloading
130131
logger.Debugf("[%s.%s] Downloading module", module.Name, module.Version)
131-
setLastOS(su, newOS(cid, module, hawkbit.StatusDownloading))
132+
setLastOS(su, newOS(cid, module, hawkbit.StatusDownloading).WithProgress(&startProgress))
132133
storage.WriteLn(s, string(hawkbit.StatusDownloading))
133134
Downloading:
134135
if opError = f.store.DownloadModule(dir, module, func(progress int) {
135-
setLastOS(su, newOS(cid, module, hawkbit.StatusDownloading).WithProgress(progress))
136+
setLastOS(su, newOS(cid, module, hawkbit.StatusDownloading).WithProgress(&progress))
136137
}, f.serverCert, f.downloadRetryCount, f.downloadRetryInterval, func() error {
137138
return f.validateLocalArtifacts(module)
138139
}); opError != nil {
@@ -143,13 +144,13 @@ Downloading:
143144

144145
// Downloaded
145146
logger.Debugf("[%s.%s] Module download finished", module.Name, module.Version)
146-
setLastOS(su, newOS(cid, module, hawkbit.StatusDownloaded).WithProgress(100))
147+
setLastOS(su, newOS(cid, module, hawkbit.StatusDownloaded).WithProgress(&completeProgress))
147148
storage.WriteLn(s, string(hawkbit.StatusDownloaded))
148149
Downloaded:
149150

150151
// Installing
151152
logger.Debugf("[%s.%s] Installing module", module.Name, module.Version)
152-
setLastOS(su, newOS(cid, module, hawkbit.StatusInstalling).WithProgress(0))
153+
setLastOS(su, newOS(cid, module, hawkbit.StatusInstalling).WithProgress(&startProgress))
153154
storage.WriteLn(s, string(hawkbit.StatusInstalling))
154155
Installing:
155156

@@ -223,7 +224,7 @@ Installing:
223224

224225
// Installed
225226
logger.Debugf("[%s.%s] Module installed", module.Name, module.Version)
226-
setLastOS(su, newFileOS(execInstallScriptDir, cid, module, hawkbit.StatusInstalled))
227+
setLastOS(su, newFileOS(execInstallScriptDir, cid, module, hawkbit.StatusInstalled).WithProgress(&completeProgress))
227228

228229
// Update installed dependencies
229230
deps, err := f.store.LoadInstalledDeps()

internal/feature_internal.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,8 @@ func newFileOS(dir string, cid string, module *storage.Module, status hawkbit.St
191191
if c != "" {
192192
ops.WithStatusCode(c)
193193
}
194-
if p >= 0 && p <= 100 {
195-
ops.WithProgress(p)
194+
if p > 0 && p <= 100 {
195+
ops.WithProgress(&p)
196196
}
197197
if m != "" {
198198
ops.WithMessage(m)

internal/feature_test.go

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -181,10 +181,10 @@ func testDisconnectWhileRunningOperation(feature *ScriptBasedSoftwareUpdatable,
181181
feature.downloadHandler(sua, feature.su)
182182
}
183183
// only 1 artifact here
184-
preDisconnectEventCount := 2 // STARTED, DOWNLOADING
185-
postDisconnectEventCount := 3 // DOWNLOADING(100)/INSTALLING(100), DOWNLOADED/INSTALLED, FINISHED_SUCCESS
184+
preDisconnectEventCount := 2 // STARTED, DOWNLOADING(0)
185+
postDisconnectEventCount := 3 // DOWNLOADING(100)/INSTALLING(100), DOWNLOADED(100)/INSTALLED(100), FINISHED_SUCCESS
186186
if install {
187-
preDisconnectEventCount = 5 // STARTED, DOWNLOADING, DOWNLOADING(100), DOWNLOADED, INSTALLING
187+
preDisconnectEventCount = 5 // STARTED, DOWNLOADING(0), DOWNLOADING(100), DOWNLOADED(100), INSTALLING(0)
188188
}
189189
statuses := pullStatusChanges(mc, preDisconnectEventCount) // should go between DOWNLOADING/INSTALLING and next state
190190

@@ -334,7 +334,7 @@ func testDownloadInstall(feature *ScriptBasedSoftwareUpdatable, mc *mockedClient
334334
// Try to execute a simple download operation.
335335
feature.downloadHandler(sua, feature.su)
336336

337-
statuses := pullStatusChanges(mc, 5+extraDownloadingEventsCount) // STARTED, DOWNLOADING, DOWNLOADING(x extraDownloadingEventsCount), DOWNLOADING(100), DOWNLOADED, FINISHED_SUCCESS
337+
statuses := pullStatusChanges(mc, 5+extraDownloadingEventsCount) // STARTED, DOWNLOADING(0), DOWNLOADING(x extraDownloadingEventsCount), DOWNLOADING(100), DOWNLOADED(100), FINISHED_SUCCESS
338338
if expectedSuccess {
339339
checkDownloadStatusEvents(extraDownloadingEventsCount, statuses, t)
340340
if copyArtifacts == "" {
@@ -349,8 +349,8 @@ func testDownloadInstall(feature *ScriptBasedSoftwareUpdatable, mc *mockedClient
349349
// Try to execute a simple install operation.
350350
feature.installHandler(sua, feature.su)
351351

352-
statuses = pullStatusChanges(mc, 8+extraDownloadingEventsCount) // STARTED, DOWNLOADING, DOWNLOADING(x extraDownloadingEventsCount), DOWNLOADING(100), DOWNLOADED,
353-
// INSTALLING, INSTALLING(100), INSTALLED, FINISHED_SUCCESS
352+
statuses = pullStatusChanges(mc, 8+extraDownloadingEventsCount) // STARTED, DOWNLOADING(0), DOWNLOADING(x extraDownloadingEventsCount), DOWNLOADING(100), DOWNLOADED(100),
353+
// INSTALLING(0), INSTALLING(100), INSTALLED(100), FINISHED_SUCCESS
354354
if expectedSuccess {
355355
checkInstallStatusEvents(extraDownloadingEventsCount, statuses, t)
356356
} else {
@@ -372,7 +372,7 @@ func checkDownloadFailedStatusEvents(actualStatuses []interface{}, t *testing.T)
372372
var expectedStatuses []interface{}
373373
expectedStatuses = append(expectedStatuses,
374374
createStatus(hawkbit.StatusStarted, nil, noMessage),
375-
createStatus(hawkbit.StatusDownloading, nil, noMessage),
375+
createStatus(hawkbit.StatusDownloading, partialProgress, noMessage),
376376
createStatus(hawkbit.StatusFinishedError, nil, anyErrorMessage),
377377
)
378378
checkStatusEvents(expectedStatuses, actualStatuses, t)
@@ -382,14 +382,14 @@ func checkDownloadStatusEvents(extraDownloadingEventsCount int, actualStatuses [
382382
var expectedStatuses []interface{}
383383
expectedStatuses = append(expectedStatuses,
384384
createStatus(hawkbit.StatusStarted, nil, noMessage),
385-
createStatus(hawkbit.StatusDownloading, nil, noMessage),
385+
createStatus(hawkbit.StatusDownloading, partialProgress, noMessage),
386386
)
387387
for i := 0; i < extraDownloadingEventsCount; i++ {
388-
expectedStatuses = append(expectedStatuses, createStatus(hawkbit.StatusDownloading, partialDownload, noMessage))
388+
expectedStatuses = append(expectedStatuses, createStatus(hawkbit.StatusDownloading, partialProgress, noMessage))
389389
}
390390
expectedStatuses = append(expectedStatuses,
391-
createStatus(hawkbit.StatusDownloading, completeDownload, noMessage),
392-
createStatus(hawkbit.StatusDownloaded, completeDownload, noMessage),
391+
createStatus(hawkbit.StatusDownloading, completeProgress, noMessage),
392+
createStatus(hawkbit.StatusDownloaded, completeProgress, noMessage),
393393
createStatus(hawkbit.StatusFinishedSuccess, nil, noMessage),
394394
)
395395
checkStatusEvents(expectedStatuses, actualStatuses, t)
@@ -399,17 +399,17 @@ func checkInstallStatusEvents(extraDownloadingEventsCount int, actualStatuses []
399399
var expectedStatuses []interface{}
400400
expectedStatuses = append(expectedStatuses,
401401
createStatus(hawkbit.StatusStarted, nil, noMessage),
402-
createStatus(hawkbit.StatusDownloading, nil, noMessage),
402+
createStatus(hawkbit.StatusDownloading, partialProgress, noMessage),
403403
)
404404
for i := 0; i < extraDownloadingEventsCount; i++ {
405-
expectedStatuses = append(expectedStatuses, createStatus(hawkbit.StatusDownloading, partialDownload, noMessage))
405+
expectedStatuses = append(expectedStatuses, createStatus(hawkbit.StatusDownloading, partialProgress, noMessage))
406406
}
407407
expectedStatuses = append(expectedStatuses,
408-
createStatus(hawkbit.StatusDownloading, completeDownload, noMessage),
409-
createStatus(hawkbit.StatusDownloaded, completeDownload, noMessage),
410-
createStatus(hawkbit.StatusInstalling, nil, noMessage),
411-
createStatus(hawkbit.StatusInstalling, nil, "My final message!"),
412-
createStatus(hawkbit.StatusInstalled, nil, "My final message!"),
408+
createStatus(hawkbit.StatusDownloading, completeProgress, noMessage),
409+
createStatus(hawkbit.StatusDownloaded, completeProgress, noMessage),
410+
createStatus(hawkbit.StatusInstalling, partialProgress, noMessage),
411+
createStatus(hawkbit.StatusInstalling, partialProgress, "My final message!"),
412+
createStatus(hawkbit.StatusInstalled, completeProgress, "My final message!"),
413413
createStatus(hawkbit.StatusFinishedSuccess, nil, "My final message!"),
414414
)
415415
checkStatusEvents(expectedStatuses, actualStatuses, t)

internal/status.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func (o *monitor) update(name string) {
4545
o.oldMessage = m
4646
o.oldStatusCode = c
4747
ops := hawkbit.NewOperationStatusUpdate(o.cid, o.status, o.module).
48-
WithProgress(p).WithMessage(m).WithStatusCode(c)
48+
WithProgress(&p).WithMessage(m).WithStatusCode(c)
4949
if err := o.su.SetLastOperation(ops); err != nil {
5050
logger.Errorf("fail to send last operation status: %v", err)
5151
}

internal/utils_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,10 @@ type testConfig struct {
7373
var (
7474
testVersion = "TestVersion"
7575

76-
partialDownload = func(progress float64) bool {
77-
return progress > 0 && progress < 100
76+
partialProgress = func(progress float64) bool {
77+
return progress >= 0 && progress < 100
7878
}
79-
completeDownload = func(progress float64) bool {
79+
completeProgress = func(progress float64) bool {
8080
return progress == 100
8181
}
8282
)

0 commit comments

Comments
 (0)