Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ require (
github.com/containers/storage v1.13.5
github.com/coreos/fcct v0.5.0
github.com/coreos/go-semver v0.3.0
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f
github.com/coreos/ign-converter v0.0.0-20200629171308-e40a44f244c5
github.com/coreos/ignition v0.35.0
github.com/coreos/ignition/v2 v2.3.0
github.com/davecgh/go-spew v1.1.1
github.com/deckarep/golang-set v1.7.1
github.com/docker/docker v1.4.2-0.20190927142053-ada3c14355ce // indirect
github.com/docker/docker-credential-helpers v0.6.3 // indirect
github.com/docker/go-connections v0.4.0 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE=
github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ=
github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/docker/distribution v0.0.0-20180920194744-16128bbac47f/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
Expand Down Expand Up @@ -290,6 +292,7 @@ github.com/go-toolsmith/typep v1.0.0 h1:zKymWyA1TRYvqYrYDrfEMZULyrhcnGY3x7LDKU2X
github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/godbus/dbus v0.0.0-20190623212516-8a1682060722 h1:NNKZiuNXd6lpZRyoFM/uhssj5W9Ps1DbhGHxT49Pm9I=
github.com/godbus/dbus v0.0.0-20190623212516-8a1682060722/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
Expand Down Expand Up @@ -554,6 +557,7 @@ github.com/openshift/build-machinery-go v0.0.0-20200424080330-082bf86082cc/go.mo
github.com/openshift/client-go v0.0.0-20190617165122-8892c0adc000/go.mod h1:6rzn+JTr7+WYS2E1TExP4gByoABxMznR6y2SnUIkmxk=
github.com/openshift/client-go v0.0.0-20200320150128-a906f3d8e723 h1:FfrELmZ9N9NtVE15qmTRkJIETX75QHdr65xiuTKvNYo=
github.com/openshift/client-go v0.0.0-20200320150128-a906f3d8e723/go.mod h1:wNBSSt4RZTHhUWyhBE3gxTR32QpF9DB2SfS14u2IxuE=
github.com/openshift/client-go v3.9.0+incompatible h1:13k3Ok0B7TA2hA3bQW2aFqn6y04JaJWdk7ITTyg+Ek0=
github.com/openshift/library-go v0.0.0-20190619114638-6b58b672ee58/go.mod h1:NBttNjZpWwup/nthuLbPAPSYC8Qyo+BBK5bCtFoyYjo=
github.com/openshift/library-go v0.0.0-20191003152030-97c62d8a2901 h1:UQkY3zDJG4MMVzS7VFsyACxs/haMJ2aHNR/jXzWhScs=
github.com/openshift/library-go v0.0.0-20191003152030-97c62d8a2901/go.mod h1:NBttNjZpWwup/nthuLbPAPSYC8Qyo+BBK5bCtFoyYjo=
Expand Down
209 changes: 209 additions & 0 deletions pkg/daemon/apply.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
package daemon

import (
"fmt"
"reflect"
"strings"

"k8s.io/client-go/tools/record"

"github.com/coreos/go-systemd/dbus"
igntypes "github.com/coreos/ignition/v2/config/v3_1/types"
mapset "github.com/deckarep/golang-set"
"github.com/golang/glog"
mcfgv1 "github.com/openshift/machine-config-operator/pkg/apis/machineconfiguration.openshift.io/v1"
ctrlcommon "github.com/openshift/machine-config-operator/pkg/controller/common"
)

type ConfigUpdateAction interface {
Describe() string
Execute(dn *Daemon, newConfig *mcfgv1.MachineConfig) error
}

type RebootPostAction struct {
ConfigUpdateAction

Reason string
}

func (a RebootPostAction) Describe() string {
return fmt.Sprintf("Rebooting node: %v", a.Reason)
}

func (a RebootPostAction) Execute(dn *Daemon, newConfig *mcfgv1.MachineConfig) error {
return dn.finalizeAndReboot(newConfig)
}

type ServicePostAction struct {
ConfigUpdateAction

Reason string

ServiceName string
ServiceAction string
}

func (a ServicePostAction) Describe() string {
return fmt.Sprintf("Restarting service %v", a.Reason)
}

func (a ServicePostAction) Execute(dn *Daemon, newConfig *mcfgv1.MachineConfig) error {
// TODO: add support for stop and reload operations if necessary
// For now only restart operation is supported

eventBroadcaster := record.NewBroadcaster()
eventBroadcaster.StartLogging(glog.V(2).Infof)

systemdConnection, dbusConnErr := dbus.NewSystemConnection()
if dbusConnErr != nil {
glog.Warningf("Unable to establish systemd dbus connection: %s", dbusConnErr)
return dbusConnErr
}

defer systemdConnection.Close()

var err error
outputChannel := make(chan string)
switch a.ServiceAction {
case "restart":
glog.Infof("Restarting unit %q", a.ServiceName)
_, err = systemdConnection.RestartUnit(a.ServiceName, "replace", outputChannel)
default:
return fmt.Errorf("Unhandled systemd action %q for %q", a.ServiceAction, a.ServiceName)
}

if err != nil {
return fmt.Errorf("Running systemd action failed: %s", err)
}

// If the provided channel is non-nil, a result string will be sent to it upon
// job completion
output := <-outputChannel
switch output {
// one of: done, canceled, timeout, failed, dependency, skipped.
case "done":
glog.Infof("Systemd action %q for %q completed successful: %s", a.ServiceAction, a.ServiceName, output)
case "skipped":
// The code suggests that 'skipped indicates that a job was
// skipped because it didn't apply to the units current state'
//
// This should only apply to stop and start actions which we
// don't support yet so treat it like an error for now
return fmt.Errorf("Systemd action %q for %q was skipped: %s", a.ServiceAction, a.ServiceName, output)
default:
return fmt.Errorf("Systemd action %q for %q failed: %s", a.ServiceAction, a.ServiceName, output)
}
return nil
}

func getFileNames(files []igntypes.File) []interface{} {
names := make([]interface{}, len(files))
for i, file := range files {
names[i] = file.Path
}
return names
}

func filesToMap(files []igntypes.File) map[string]igntypes.File {
fileMap := make(map[string]igntypes.File, len(files))
for _, file := range files {
fileMap[file.Path] = file
}
return fileMap
}

type ChangeStrategy struct {
actions []ConfigUpdateAction
}

func lookupStrategy(stripPrefix, filePath string) ([]ConfigUpdateAction, error) {

strategies := map[string]ChangeStrategy{
"/etc/containers/registries.conf": {
actions: []ConfigUpdateAction{
ServicePostAction{
Reason: "Change to /etc/containers/registries.conf",
ServiceName: "crio.service",
ServiceAction: "restart",
},
},
},
}

key := filePath
if len(stripPrefix) > 0 {
key = strings.TrimPrefix(filePath, stripPrefix)
}

if strategy, ok := strategies[key]; ok {
return strategy.actions, nil
}
return []ConfigUpdateAction{}, fmt.Errorf("Default strategy for applying changes to %q", key)
}

func getFileChanges(stripPrefix string, oldIgnConfig, newIgnConfig igntypes.Config) []ConfigUpdateAction {
actions := []ConfigUpdateAction{}

oldFiles := mapset.NewSetFromSlice(getFileNames(oldIgnConfig.Storage.Files))
newFiles := mapset.NewSetFromSlice(getFileNames(newIgnConfig.Storage.Files))

for filename := range newFiles.Difference(oldFiles).Iter() {
return []ConfigUpdateAction{RebootPostAction{Reason: fmt.Sprintf("File %q was added", filename.(string))}}
}

for filename := range oldFiles.Difference(newFiles).Iter() {
return []ConfigUpdateAction{RebootPostAction{Reason: fmt.Sprintf("File %q was removed", filename.(string))}}
}

newFilesMap := filesToMap(newIgnConfig.Storage.Files)
for file := range newFiles.Intersect(oldFiles).Iter() {
candidate := newFilesMap[file.(string)]
if err := checkV3Files([]igntypes.File{candidate}); err != nil {
strategyActions, err := lookupStrategy(stripPrefix, candidate.Node.Path)
if err == nil {
for _, a := range strategyActions {
actions = append(actions, a)
}
} else {
return []ConfigUpdateAction{RebootPostAction{Reason: err.Error()}}
}
}
}

return actions
}

func calculateActions(stripPrefix string, oldConfig, newConfig *mcfgv1.MachineConfig, diff *machineConfigDiff) []ConfigUpdateAction {

if diff.osUpdate || diff.kargs || diff.fips || diff.kernelType {
return []ConfigUpdateAction{RebootPostAction{Reason: "OS/Kernel changed"}}
}

oldIgnConfig, err := ctrlcommon.ParseAndConvertConfig(oldConfig.Spec.Config.Raw)
if err != nil {
return []ConfigUpdateAction{RebootPostAction{
Reason: fmt.Sprintf("parsing old Ignition config failed with error: %v", err)}}
}
newIgnConfig, err := ctrlcommon.ParseAndConvertConfig(newConfig.Spec.Config.Raw)
if err != nil {
return []ConfigUpdateAction{RebootPostAction{
Reason: fmt.Sprintf("parsing new Ignition config failed with error: %v", err)}}
}

// Check for any changes not already excluded by Reconcilable()
// Alternatively, fold this code into that function
if !reflect.DeepEqual(oldIgnConfig.Ignition, newIgnConfig.Ignition) {
return []ConfigUpdateAction{RebootPostAction{Reason: "Ignition changed"}}
}
if !reflect.DeepEqual(oldIgnConfig.Passwd, newIgnConfig.Passwd) {
return []ConfigUpdateAction{RebootPostAction{Reason: "Passwords changed"}}
}
if !reflect.DeepEqual(oldIgnConfig.Systemd, newIgnConfig.Systemd) {
return []ConfigUpdateAction{RebootPostAction{Reason: "Systemd configuration changed"}}
}
if !reflect.DeepEqual(oldIgnConfig.Storage.Files, newIgnConfig.Storage.Files) {
return getFileChanges(stripPrefix, oldIgnConfig, newIgnConfig)
}

return []ConfigUpdateAction{}
}
Loading