Skip to content

Commit

Permalink
[#201] Optimized, deterministic intermediate desired state feedback m…
Browse files Browse the repository at this point in the history
…essages (#204)

+ added unit tests for update agent command processing and feedback messages

Signed-off-by: Stoyan Zoubev <Stoyan.Zoubev@bosch.com>
  • Loading branch information
stoyan-zoubev authored and k-gostev committed Apr 30, 2024
1 parent 7923854 commit 7c7ab88
Show file tree
Hide file tree
Showing 3 changed files with 967 additions and 33 deletions.
6 changes: 6 additions & 0 deletions containerm/updateagent/update_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,10 @@ func createSimpleContainer(name, version string) *ctrtypes.Container {
ctr := &ctrtypes.Container{
Name: name,
Image: ctrtypes.Image{Name: name + ":" + version},
State: &ctrtypes.State{},
}
util.FillDefaults(ctr)
util.SetContainerStatusRunning(ctr, 1234)
return ctr
}

Expand All @@ -310,3 +312,7 @@ func createSimpleDesiredComponent(name, version string) *types.ComponentWithConf
Component: types.Component{ID: name, Version: version},
}
}

func createActionComponent(component *types.ComponentWithConfig) *types.Component {
return &types.Component{ID: domainName + ":" + component.ID, Version: component.Version}
}
84 changes: 51 additions & 33 deletions containerm/updateagent/update_operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,20 +267,19 @@ func download(o *operation, baselineAction *baselineAction) {

actions := baselineAction.actions
for _, action := range actions {
if lastAction != nil {
o.updateBaselineActionStatus(baselineAction, types.BaselineStatusDownloading, lastAction, types.ActionStatusDownloadSuccess, lastActionMessage)
}
lastAction = action
if action.actionType == util.ActionCreate || action.actionType == util.ActionRecreate {
if lastAction != nil {
lastAction.feedbackAction.Status = types.ActionStatusDownloadSuccess
lastAction.feedbackAction.Message = lastActionMessage
}
lastAction = action
o.updateBaselineActionStatus(baselineAction, types.BaselineStatusDownloading, action, types.ActionStatusDownloading, action.feedbackAction.Message)
log.Debug("new container %s to be created...", action.feedbackAction.Component.ID)
if err := o.createContainer(action.desired); err != nil {
lastActionErr = err
return
}
lastActionMessage = "New container created."
} else {
lastAction = nil
}
}
}
Expand All @@ -304,28 +303,29 @@ func update(o *operation, baselineAction *baselineAction) {

actions := baselineAction.actions
for _, action := range actions {
if action.actionType != util.ActionRecreate && action.actionType != util.ActionDestroy && action.actionType != util.ActionUpdate {
continue
}
if lastAction != nil {
o.updateBaselineActionStatus(baselineAction, types.BaselineStatusUpdating, lastAction, types.ActionStatusUpdateSuccess, lastActionMessage)
lastAction.feedbackAction.Status = types.ActionStatusUpdateSuccess
lastAction.feedbackAction.Message = lastActionMessage
}
lastAction = action

log.Debug("container %s to be updated...", action.feedbackAction.Component.ID)
lastAction = action
o.updateBaselineActionStatus(baselineAction, types.BaselineStatusUpdating, action, types.ActionStatusUpdating, action.feedbackAction.Message)
if action.actionType == util.ActionRecreate || action.actionType == util.ActionDestroy {
o.updateBaselineActionStatus(baselineAction, types.BaselineStatusUpdating, action, types.ActionStatusUpdating, action.feedbackAction.Message)
if err := o.stopContainer(action.current); err != nil {
lastActionErr = err
return
}
lastActionMessage = "Old container instance is stopped."
} else if action.actionType == util.ActionUpdate {
o.updateBaselineActionStatus(baselineAction, types.BaselineStatusUpdating, action, types.ActionStatusUpdating, action.feedbackAction.Message)
} else { // action.actionType == util.ActionUpdate
if err := o.updateContainer(action.current, action.desired); err != nil {
lastActionErr = err
return
}
lastActionMessage = "Container instance is updated with new configuration."
} else {
lastActionMessage = action.feedbackAction.Message
}
}
}
Expand All @@ -349,14 +349,18 @@ func activate(o *operation, baselineAction *baselineAction) {

actions := baselineAction.actions
for _, action := range actions {
if action.actionType == util.ActionDestroy {
continue
}
if lastAction != nil {
o.updateBaselineActionStatus(baselineAction, types.BaselineStatusActivating, lastAction, types.ActionStatusActivationSuccess, lastActionMessage)
lastAction.feedbackAction.Status = types.ActionStatusActivationSuccess
lastAction.feedbackAction.Message = lastActionMessage
}
lastAction = action

log.Debug("container %s to be activated...", action.feedbackAction.Component.ID)
lastAction = action
o.updateBaselineActionStatus(baselineAction, types.BaselineStatusActivating, action, types.ActionStatusActivating, action.feedbackAction.Message)
if action.actionType == util.ActionCheck || action.actionType == util.ActionUpdate {
o.updateBaselineActionStatus(baselineAction, types.BaselineStatusActivating, action, types.ActionStatusActivating, action.feedbackAction.Message)
if err := o.ensureRunningContainer(action.current); err != nil {
lastActionErr = err
return
Expand All @@ -367,14 +371,11 @@ func activate(o *operation, baselineAction *baselineAction) {
lastActionMessage = action.feedbackAction.Message
}
} else if action.actionType == util.ActionCreate || action.actionType == util.ActionRecreate {
o.updateBaselineActionStatus(baselineAction, types.BaselineStatusActivating, action, types.ActionStatusActivating, action.feedbackAction.Message)
if err := o.startContainer(action.desired); err != nil {
lastActionErr = err
return
}
lastActionMessage = "New container instance is started."
} else {
lastAction = nil
}
}
}
Expand Down Expand Up @@ -451,24 +452,41 @@ func cleanup(o *operation, baselineAction *baselineAction) {
} else {
delete(o.baselineActions, baseline)
}
log.Debug("cleanup for baseline %s - starting...", baseline)
for _, action := range actions {
if action.actionType == util.ActionRecreate || action.actionType == util.ActionDestroy {
log.Debug("container %s to be cleanup...", action.feedbackAction.Component.ID)
err := o.removeContainer(action.current)
if action.actionType == util.ActionDestroy {
if err != nil {
action.feedbackAction.Status = types.ActionStatusRemovalFailure
action.feedbackAction.Message = err.Error()
} else {
action.feedbackAction.Status = types.ActionStatusRemovalSuccess
action.feedbackAction.Message = "Old container instance is removed."

log.Debug("cleanup for baseline %s (%s) - starting...", baseline, baselineAction.status)
result := types.BaselineStatusCleanupSuccess
if baselineAction.status != types.BaselineStatusActivationSuccess {
log.Warn("cleanup implemented only for successfully activated baselines, no cleanup for baseline %s (%s)", baseline, baselineAction.status)
// TODO implement cleanup for failure scenarios, maybe together with rollback
} else {
for _, action := range actions {
if action.actionType == util.ActionRecreate || action.actionType == util.ActionDestroy {
log.Debug("container %s to be cleanup...", action.feedbackAction.Component.ID)
err := o.removeContainer(action.current)
if action.feedbackAction.Status == types.ActionStatusUpdateSuccess && action.actionType == util.ActionDestroy {
if err != nil {
action.feedbackAction.Status = types.ActionStatusRemovalFailure
action.feedbackAction.Message = err.Error()
result = types.BaselineStatusCleanupFailure
} else {
action.feedbackAction.Status = types.ActionStatusRemovalSuccess
action.feedbackAction.Message = "Old container instance is removed."
}
}
}
}
}
o.Feedback(types.BaselineStatusCleanupSuccess, "", baseline)
log.Debug("cleanup for baseline %s - done...", baseline)
o.Feedback(result, "", baseline)
log.Debug("cleanup for baseline (%s) %s - done...", baseline, baselineAction.status)

if len(o.baselineActions) == 0 {
o.updateManager.operation = nil
if baselineAction.status == types.BaselineStatusActivationSuccess && result == types.BaselineStatusCleanupSuccess {
o.Feedback(types.StatusCompleted, "", "")
} else {
o.Feedback(types.StatusIncomplete, "", "")
}
}
}

func (o *operation) isSystemContainer(containerID string) bool {
Expand Down
Loading

0 comments on commit 7c7ab88

Please sign in to comment.