diff --git a/hawkbit/lib_software_module_id.go b/hawkbit/lib_software_module_id.go index bc222d0..6db78e0 100644 --- a/hawkbit/lib_software_module_id.go +++ b/hawkbit/lib_software_module_id.go @@ -16,6 +16,7 @@ package hawkbit const ( softwareModuleNameParam = "name" softwareModuleVersionParam = "version" + softwareModuleStoredPath = "path" ) // SoftwareModuleID represents an unique identifier for software modules. @@ -24,4 +25,6 @@ type SoftwareModuleID struct { Name string `json:"name"` // Version of the software module. Version string `json:"version"` + // Stored downloaded file path + Path string `json:"path,omitempty"` } diff --git a/hawkbit/lib_status.go b/hawkbit/lib_status.go index 7bd7d1e..b2b68c8 100644 --- a/hawkbit/lib_status.go +++ b/hawkbit/lib_status.go @@ -17,21 +17,22 @@ type Status string // Supported operation statuses. const ( - StatusStarted Status = "STARTED" - StatusDownloading Status = "DOWNLOADING" - StatusDownloadingWaiting Status = "DOWNLOADING_WAITING" - StatusDownloaded Status = "DOWNLOADED" - StatusInstalling Status = "INSTALLING" - StatusInstallingWaiting Status = "INSTALLING_WAITING" - StatusInstalled Status = "INSTALLED" - StatusRemoving Status = "REMOVING" - StatusRemovingWaiting Status = "REMOVING_WAITING" - StatusRemoved Status = "REMOVED" - StatusCancelingWaiting Status = "CANCELING_WAITING" - StatusCancelRejected Status = "CANCEL_REJECTED" - StatusFinishedCanceled Status = "FINISHED_CANCELED" - StatusFinishedError Status = "FINISHED_ERROR" - StatusFinishedSuccess Status = "FINISHED_SUCCESS" - StatusFinishedWarning Status = "FINISHED_WARNING" - StatusFinishedRejected Status = "FINISHED_REJECTED" + StatusStarted Status = "STARTED" + StatusDownloading Status = "DOWNLOADING" + StatusDownloadingWaiting Status = "DOWNLOADING_WAITING" + StatusDownloaded Status = "DOWNLOADED" + StatusDownloadedFileStored Status = "DOWNLOADED_FILE_STORED" + StatusInstalling Status = "INSTALLING" + StatusInstallingWaiting Status = "INSTALLING_WAITING" + StatusInstalled Status = "INSTALLED" + StatusRemoving Status = "REMOVING" + StatusRemovingWaiting Status = "REMOVING_WAITING" + StatusRemoved Status = "REMOVED" + StatusCancelingWaiting Status = "CANCELING_WAITING" + StatusCancelRejected Status = "CANCEL_REJECTED" + StatusFinishedCanceled Status = "FINISHED_CANCELED" + StatusFinishedError Status = "FINISHED_ERROR" + StatusFinishedSuccess Status = "FINISHED_SUCCESS" + StatusFinishedWarning Status = "FINISHED_WARNING" + StatusFinishedRejected Status = "FINISHED_REJECTED" ) diff --git a/hawkbit/software_updatable.go b/hawkbit/software_updatable.go index 1082db1..5881327 100644 --- a/hawkbit/software_updatable.go +++ b/hawkbit/software_updatable.go @@ -140,10 +140,16 @@ func MapLastOperation(LastOperationPtr *OperationStatus) map[string]interface{} lastOperationMap[statusParam] = LastOperationPtr.Status if LastOperationPtr.SoftwareModule != nil { - lastOperationMap[softwareModuleParam] = map[string]interface{}{ + innerMap := map[string]interface{}{ softwareModuleNameParam: LastOperationPtr.SoftwareModule.Name, softwareModuleVersionParam: LastOperationPtr.SoftwareModule.Version, } + + if LastOperationPtr.SoftwareModule.Path != "" { + innerMap[softwareModuleStoredPath] = LastOperationPtr.SoftwareModule.Path + } + + lastOperationMap[softwareModuleParam] = innerMap } if LastOperationPtr.Software != nil { @@ -195,3 +201,8 @@ func (su *SoftwareUpdatable) SetLastOperation(os *OperationStatus) error { } return su.setProperty(suPropertyLastOperation, MapLastOperation(su.status.LastOperation)) } + +// GetLastStatus returns the recorded last operation status +func (su *SoftwareUpdatable) GetLastStatus() *softwareUpdatableStatus { + return su.status +} diff --git a/internal/feature_download.go b/internal/feature_download.go index 53323c9..e2dde46 100644 --- a/internal/feature_download.go +++ b/internal/feature_download.go @@ -52,9 +52,14 @@ func (f *ScriptBasedSoftwareUpdatable) downloadModules( } // Archive all modules. - for i, module := range updatable.Modules { - if err := f.store.ArchiveModule(filepath.Join(toDir, strconv.Itoa(i))); err != nil { - logger.Errorf("failed to archive module [%s.%s]: %v", module.Name, module.Version, err) + if su.GetLastStatus().LastOperation.Status == hawkbit.StatusFinishedSuccess { + for i, module := range updatable.Modules { + if err := f.store.ArchiveModule(filepath.Join(toDir, strconv.Itoa(i)), &module.Path); err != nil { + logger.Errorf("failed to archive module [%s.%s]: %v", module.Name, module.Version, err) + } else { + logger.Debugf("Archived downloaded file path: %s", module.Path) + setLastOS(su, newOS(updatable.CorrelationID, module, hawkbit.StatusDownloadedFileStored)) + } } } diff --git a/internal/feature_internal.go b/internal/feature_internal.go index 4a284ff..1ce1662 100644 --- a/internal/feature_internal.go +++ b/internal/feature_internal.go @@ -175,7 +175,7 @@ func (f *ScriptBasedSoftwareUpdatable) fail(cid string, modules []*hawkbit.Softw // newOS returns newly created OperationStatus pointer. func newOS(cid string, module *storage.Module, status hawkbit.Status) *hawkbit.OperationStatus { return hawkbit.NewOperationStatusUpdate(cid, status, - &hawkbit.SoftwareModuleID{Name: module.Name, Version: module.Version}) + &hawkbit.SoftwareModuleID{Name: module.Name, Version: module.Version, Path: module.Path}) } // newFileOS returns newly created OperationStatus pointer, filled with the status file data. diff --git a/internal/feature_test.go b/internal/feature_test.go index 80a38c2..b2200bf 100644 --- a/internal/feature_test.go +++ b/internal/feature_test.go @@ -185,15 +185,18 @@ func testDisconnectWhileRunningOperation(feature *ScriptBasedSoftwareUpdatable, postDisconnectEventCount := 3 // DOWNLOADING(100)/INSTALLING(100), DOWNLOADED(100)/INSTALLED(100), FINISHED_SUCCESS if install { preDisconnectEventCount = 5 // STARTED, DOWNLOADING(0), DOWNLOADING(100), DOWNLOADED(100), INSTALLING(0) + } else { + postDisconnectEventCount += 1 //DOWNLOADED_FILE_STORED } - statuses := pullStatusChanges(mc, preDisconnectEventCount) // should go between DOWNLOADING/INSTALLING and next state + + statuses := pullStatusChanges(mc, install, preDisconnectEventCount) // should go between DOWNLOADING/INSTALLING and next state go func() { // decrements count number with 1, when disconnected feature.Disconnect(false) waitDisconnect.Done() }() - statuses = append(statuses, pullStatusChanges(mc, postDisconnectEventCount)...) + statuses = append(statuses, pullStatusChanges(mc, install, postDisconnectEventCount)...) waitDisconnect.Wait() defer connectFeature(t, mc, feature, NewDefaultConfig().FeatureID) if install { @@ -310,13 +313,19 @@ func testScriptBasedSoftwareUpdatableOperationsLocal(t *testing.T, installDirs [ testDownloadInstall(feature, mc, artifacts, expectedSuccess, copyArtifacts, t) } -func pullStatusChanges(mc *mockedClient, expectedCount int) []interface{} { +func pullStatusChanges(mc *mockedClient, install bool, expectedCount int) []interface{} { var statuses []interface{} for i := 0; i < expectedCount; i++ { lo := mc.pullLastOperationStatus() statuses = append(statuses, lo) - if lo["status"] == string(hawkbit.StatusFinishedSuccess) || lo["status"] == string(hawkbit.StatusFinishedError) { - break + if install { + if lo["status"] == string(hawkbit.StatusFinishedSuccess) || lo["status"] == string(hawkbit.StatusFinishedError) { + break + } + } else { + if lo["status"] == string(hawkbit.StatusDownloadedFileStored) || lo["status"] == string(hawkbit.StatusFinishedError) { + break + } } } return statuses @@ -334,7 +343,8 @@ func testDownloadInstall(feature *ScriptBasedSoftwareUpdatable, mc *mockedClient // Try to execute a simple download operation. feature.downloadHandler(sua, feature.su) - statuses := pullStatusChanges(mc, 5+extraDownloadingEventsCount) // STARTED, DOWNLOADING(0), DOWNLOADING(x extraDownloadingEventsCount), DOWNLOADING(100), DOWNLOADED(100), FINISHED_SUCCESS + statuses := pullStatusChanges(mc, false, 6+extraDownloadingEventsCount) // STARTED, DOWNLOADING(0), DOWNLOADING(x extraDownloadingEventsCount), + // DOWNLOADING(100), DOWNLOADED(100), FINISHED_SUCCESS, DOWNLOADED_FILE_STORED if expectedSuccess { checkDownloadStatusEvents(extraDownloadingEventsCount, statuses, t) if copyArtifacts == "" { @@ -349,7 +359,8 @@ func testDownloadInstall(feature *ScriptBasedSoftwareUpdatable, mc *mockedClient // Try to execute a simple install operation. feature.installHandler(sua, feature.su) - statuses = pullStatusChanges(mc, 8+extraDownloadingEventsCount) // STARTED, DOWNLOADING(0), DOWNLOADING(x extraDownloadingEventsCount), DOWNLOADING(100), DOWNLOADED(100), + statuses = pullStatusChanges(mc, true, 8+extraDownloadingEventsCount) // STARTED, DOWNLOADING(0), DOWNLOADING(x extraDownloadingEventsCount), + //DOWNLOADING(100), DOWNLOADED(100), // INSTALLING(0), INSTALLING(100), INSTALLED(100), FINISHED_SUCCESS if expectedSuccess { checkInstallStatusEvents(extraDownloadingEventsCount, statuses, t) @@ -391,6 +402,7 @@ func checkDownloadStatusEvents(extraDownloadingEventsCount int, actualStatuses [ createStatus(hawkbit.StatusDownloading, completeProgress, noMessage), createStatus(hawkbit.StatusDownloaded, completeProgress, noMessage), createStatus(hawkbit.StatusFinishedSuccess, nil, noMessage), + createStatus(hawkbit.StatusDownloadedFileStored, nil, noMessage), ) checkStatusEvents(expectedStatuses, actualStatuses, t) } diff --git a/internal/storage/storage.go b/internal/storage/storage.go index a882d43..bd54667 100644 --- a/internal/storage/storage.go +++ b/internal/storage/storage.go @@ -58,6 +58,7 @@ type Updatable struct { type Module struct { Name string `json:"name"` Version string `json:"version"` + Path string `json:"path,omitempty"` Artifacts []*Artifact `json:"artifacts,omitempty"` Metadata map[string]string `json:"metadata,omitempty"` } @@ -212,12 +213,13 @@ func (st *Storage) MoveInstalledDeps(dir string, metadata map[string]string) err } // ArchiveModule to modules directory. -func (st *Storage) ArchiveModule(dir string) error { +func (st *Storage) ArchiveModule(dir string, dest *string) error { logger.Debugf("Archive module from directory: %s", dir) path, err := FindAvailableLocation(st.ModulesPath) if err != nil { return err } + *dest = path if err := os.MkdirAll(path, 0755); err != nil { return err } diff --git a/internal/storage/storage_test.go b/internal/storage/storage_test.go index 3953f39..421edd2 100644 --- a/internal/storage/storage_test.go +++ b/internal/storage/storage_test.go @@ -248,10 +248,11 @@ func TestDownloadArchiveModule(t *testing.T) { existence(filepath.Join(path, art.FileName), true, "[initial download]", t) // 2. Archive module. + storedPath := "" if err := WriteLn(filepath.Join(path, InternalStatusName), m.Name+":"+m.Version); err != nil { t.Fatalf("fail to write module id: %v", err) } - if err := store.ArchiveModule(path); err != nil { + if err := store.ArchiveModule(path, &storedPath); err != nil { t.Fatalf("fail to archive module: %v", err) } existence(filepath.Join(store.ModulesPath, "0", art.FileName), true, "[archive]", t)