Skip to content

Instantly share code, notes, and snippets.

@beekhof
Last active July 10, 2020 10:12
Show Gist options
  • Save beekhof/a0312eed54ac03cca9e33ed4f38b980c to your computer and use it in GitHub Desktop.
Save beekhof/a0312eed54ac03cca9e33ed4f38b980c to your computer and use it in GitHub Desktop.
diff --git a/pkg/daemon/update.go b/pkg/daemon/update.go
index 773246cb..4dfd9325 100644
--- a/pkg/daemon/update.go
+++ b/pkg/daemon/update.go
@@ -17,6 +17,8 @@ import (
"syscall"
"time"
+ "github.com/openshift/machine-config-operator/pkg/daemon/pivot/reboot"
+
ign "github.com/coreos/ignition/config/v2_2"
igntypes "github.com/coreos/ignition/config/v2_2/types"
"github.com/golang/glog"
@@ -24,7 +26,6 @@ import (
mcfgv1 "github.com/openshift/machine-config-operator/pkg/apis/machineconfiguration.openshift.io/v1"
ctrlcommon "github.com/openshift/machine-config-operator/pkg/controller/common"
"github.com/openshift/machine-config-operator/pkg/daemon/constants"
- "github.com/openshift/machine-config-operator/pkg/daemon/pivot/reboot"
pivotutils "github.com/openshift/machine-config-operator/pkg/daemon/pivot/utils"
errors "github.com/pkg/errors"
"github.com/vincent-petithory/dataurl"
@@ -280,6 +281,129 @@ func (dn *Daemon) compareMachineConfig(oldConfig, newConfig *mcfgv1.MachineConfi
return true, nil
}
+type actionResult interface {
+ Describe(dn *Daemon) string
+ Execute(dn *Daemon, newConfig *mcfgv1.MachineConfig) error
+}
+
+type NoOpPostAction struct {
+ actionResult
+}
+
+func (a NoOpPostAction)Describe(dn *Daemon) string {
+ return "No action needed to apply update"
+}
+
+func (a NoOpPostAction)Execute(dn *Daemon, newConfig *mcfgv1.MachineConfig) error {
+ return nil
+}
+
+type RebootPostAction struct {
+ actionResult
+
+ Reason string
+}
+
+func (a RebootPostAction)Describe(dn *Daemon) string {
+ return fmt.Sprintf("Rebooting node %v: %v", dn.node.GetName(), a.Reason)
+}
+
+func (a RebootPostAction)Execute(dn *Daemon, newConfig *mcfgv1.MachineConfig) error {
+ return dn.drainAndReboot(newConfig)
+}
+
+type DrainPostAction struct {
+ actionResult
+}
+
+func (a DrainPostAction)Describe(dn *Daemon) string {
+ return fmt.Sprintf("Draining node %v", dn.node.GetName())
+}
+
+func (a DrainPostAction)Execute(dn *Daemon, newConfig *mcfgv1.MachineConfig) error {
+ return dn.drain()
+}
+
+type ServicePostAction struct {
+ actionResult
+
+ Reason string
+
+ ServiceName string
+ ServiceAction string
+}
+
+
+func (a ServicePostAction)Describe(dn *Daemon) string {
+ return fmt.Sprintf("Restarting service %v", a.Reason)
+}
+
+func (a ServicePostAction)Execute(dn *Daemon, newConfig *mcfgv1.MachineConfig) error {
+ return nil
+}
+
+
+type SchedulablePostAction struct {
+ actionResult
+}
+
+func (a SchedulablePostAction)Describe(dn *Daemon) string {
+ return fmt.Sprintf("Uncordoning node %v", dn.node.GetName())
+}
+
+func (a SchedulablePostAction)Execute(dn *Daemon, newConfig *mcfgv1.MachineConfig) error {
+ return drain.RunCordonOrUncordon(dn.drainer, dn.node, false)
+}
+
+func calculateActions(oldIgnConfig, newIgnConfig igntypes.Config, diff *MachineConfigDiff) []actionResult {
+ if diff.osUpdate || diff.kargs || diff.fips || diff.kernelType {
+ return []actionResult{RebootPostAction{Reason: "OS/Kernel changed"}}
+ }
+ if !reflect.DeepEqual(oldIgnConfig.Ignition, newIgnConfig.Ignition) {
+ return []actionResult{RebootPostAction{Reason: "Ignition changed"}}
+ }
+ if !reflect.DeepEqual(oldIgnConfig.Networkd, newIgnConfig.Networkd) {
+ return []actionResult{RebootPostAction{Reason: "Network changed"}}
+ }
+ if !reflect.DeepEqual(oldIgnConfig.Passwd, newIgnConfig.Passwd) {
+ return []actionResult{RebootPostAction{Reason: "Passwords changed"}}
+ }
+ if !reflect.DeepEqual(oldIgnConfig.Systemd, newIgnConfig.Systemd) {
+ return []actionResult{RebootPostAction{Reason: "Systemd changed"}}
+ }
+ if !reflect.DeepEqual(oldIgnConfig.Storage, newIgnConfig.Storage) {
+ actions = []actionResult{}
+
+ icspRegex := regexp.MustCompile(".*/registry.conf")
+
+ fileChanges = reboot.getFilesChanges(oldIgnConfig.Storage.Files, newIgnConfig.Storage.Files)
+ for _, change := range fileChanges {
+ matched, err := icspRegex.MatchString(change.name)
+ if err != nil {
+ return []actionResult{RebootPostAction{Reason: "Error processing storage changes"}}
+ }
+ if !matched {
+ return []actionResult{RebootPostAction{Reason: "Storage changed"}}
+ }
+
+ if len(actions) == 0 {
+ actions = append(actions, DrainPostAction{})
+ }
+ actions = append(actions, ServicePostAction{
+ Reason: fmt.Sprintf("change to %v", change.name),
+ ServiceName: "crio.service", ServiceAction: "restart"})
+ }
+
+ if len(actions) > 0 {
+ actions = append(actions, SchedulablePostAction{})
+ return actions
+ }
+ }
+
+ return []actionResult{NoOpPostAction{}}
+}
+
+
// update the node to the provided node configuration.
func (dn *Daemon) update(oldConfig, newConfig *mcfgv1.MachineConfig) (retErr error) {
oldConfig = canonicalizeEmptyMC(oldConfig)
@@ -334,18 +458,20 @@ func (dn *Daemon) update(oldConfig, newConfig *mcfgv1.MachineConfig) (retErr err
}
dn.logSystem("Starting update from %s to %s: %+v", oldConfigName, newConfigName, diff)
- rebootRequired := diff.osUpdate || diff.kargs || diff.fips || diff.kernelType
- rebootFilter := reboot.NewFilter(oldIgnConfig, newIgnConfig)
- drainRequired := rebootFilter.IsRebootRequired || rebootFilter.IsDrainRequired
+ actions := dn.calculateActions(oldIgnConfig, newIgnConfig, diff)
- if drainRequired {
- if err := dn.drain(); err != nil {
- return err
+ for _, action := range actions {
+ switch action.(type) {
+ case DrainPostAction:
+ glog.Infof("Performing %v", action.Describe(dn))
+ if err := action.Execute(dn, newConfig); err != nil {
+ glog.Errorf("Uncordoning node failed, node will reboot: %v", err)
+ return dn.finalizeAndReboot(newConfig)
+ }
+ default:
+ continue
}
- } else {
- glog.Info("Draining node skipped as it is not required")
- }
// update files on disk that need updating
if err := dn.updateFiles(oldConfig, newConfig); err != nil {
@@ -416,10 +542,20 @@ func (dn *Daemon) update(oldConfig, newConfig *mcfgv1.MachineConfig) (retErr err
if err := dn.updateOS(newConfig); err != nil {
return err
}
- if rebootRequired || rebootFilter.RunPostUpdateActions() {
- return dn.drainAndReboot(newConfig)
+
+ for _, action := range actions {
+ switch action.(type) {
+ case DrainPostAction:
+ continue
+ default:
+ glog.Infof("Performing %v", action.Describe(dn))
+ if err := action.Execute(dn, newConfig); err != nil {
+ glog.Errorf("Uncordoning node failed, node will reboot: %v", err)
+ return dn.finalizeAndReboot(newConfig)
+ }
+ }
}
- glog.Info("Reboot skipped as it is not required")
+
if err := dn.nodeWriter.SetDone(
dn.kubeClient.CoreV1().Nodes(),
dn.nodeLister,
@@ -429,13 +565,6 @@ func (dn *Daemon) update(oldConfig, newConfig *mcfgv1.MachineConfig) (retErr err
glog.Errorf("Setting node's state to Done failed, node will reboot: %v", err)
return dn.drainAndReboot(newConfig)
}
- if drainRequired {
- glog.Infof("Starting uncordoning node %v", dn.node.GetName())
- if err := drain.RunCordonOrUncordon(dn.drainer, dn.node, false); err != nil {
- glog.Errorf("Uncordoning node failed, node will reboot: %v", err)
- return dn.finalizeAndReboot(newConfig)
- }
- }
glog.Infof("In desired config %s", newConfigName)
MCDUpdateState.WithLabelValues(newConfigName, "").SetToCurrentTime()
return nil
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment