...
1 package patchmanager
2
3 import (
4 "context"
5 "fmt"
6 "os"
7 "path/filepath"
8
9 "github.com/go-logr/logr"
10 "github.com/spf13/afero"
11
12 file "edge-infra.dev/pkg/sds/lib/os/file"
13 "edge-infra.dev/pkg/sds/patching/common"
14 v1patch "edge-infra.dev/pkg/sds/patching/k8s/apis/ienpatch/v1"
15
16 k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
17 )
18
19 type PatchManager struct {
20 Ctx context.Context
21 K8sClient k8sclient.Client
22 Log logr.Logger
23 HostName string
24 Ienpatch *v1patch.IENPatch
25 CurrentVer string
26 TargetVer string
27 Fs afero.OsFs
28 Cfg common.Config
29 }
30
31 func (p *PatchManager) PatchIEN() (v1patch.PatchStatus, error) {
32
33 if err := remount(p.Cfg.MountPath); err != nil {
34 return v1patch.Retry, err
35 }
36
37 if err := p.installPatchset(); err != nil {
38 return v1patch.Retry, fmt.Errorf("Failed to unpack and install patchset: %w", err)
39 }
40
41 if p.Ienpatch.Spec.DownloadOnly {
42 p.Log.Info("Download and extraction complete. Set downloadOnly to false to continue patching")
43 return v1patch.DownloadComplete, nil
44 }
45
46 if !p.isNodeTargetted() {
47 return v1patch.Pending, nil
48 }
49
50 if err := p.WaitForRebootAllowed(); err != nil {
51 return v1patch.Retry, fmt.Errorf("Error occurred while waiting to see if reboot is possible: %w", err)
52 }
53
54 if err := generatePatchingEnv(p.CurrentVer, p.TargetVer, p.Cfg.EnvFilePath); err != nil {
55 return v1patch.Retry, fmt.Errorf("Failed to generate patching.env file: %w", err)
56 }
57
58 if err := generatePatchingEnv(p.CurrentVer, p.TargetVer, common.EnvFilePath); err != nil {
59 return v1patch.Retry, fmt.Errorf("Failed to generate patching.env file: %w", err)
60 }
61
62 if err := requestReboot(p.Ienpatch.Spec.AutoReboot, p.Log, p.Cfg); err != nil {
63 return v1patch.Failed, fmt.Errorf("Failed to schedule reboot: %w", err)
64 }
65 return v1patch.Reboot, nil
66 }
67
68 func Contains(nodeList []string, nodeName string) bool {
69 for _, v := range nodeList {
70 if v == nodeName {
71 return true
72 }
73 }
74 return false
75 }
76
77 func generatePatchingEnv(currentVer, targetVer string, path string) error {
78 data := []byte(fmt.Sprintf("CURRENT='%s'\nTARGET='%s'\n", currentVer, targetVer))
79 return os.WriteFile(path, data, 0600)
80 }
81
82 func requestReboot(autoreboot bool, log logr.Logger, cfg common.Config) error {
83 if !autoreboot {
84 log.Info("Auto reboot is disabled. Please manually reboot the system")
85 return nil
86 }
87
88 perms := os.FileMode(0755)
89
90 if err := os.MkdirAll(filepath.Dir(cfg.RebootPath), perms); err != nil {
91 return err
92 }
93
94 if _, err := os.Create(cfg.RebootPath); err != nil {
95 return err
96 }
97
98 if err := os.Chmod(cfg.RebootPath, perms); err != nil {
99 return err
100 }
101
102 log.Info("Auto reboot scheduled, waiting for reboot daemon")
103 return nil
104 }
105
106
107 func remount(mountPath string) error {
108 fileHandler := file.New()
109
110 mountInfo, err := fileHandler.GetMountInfo(mountPath)
111 if err != nil {
112 return fmt.Errorf("Failed to get mount info for mountPath %s: %w", mountPath, err)
113 }
114
115 if remountErr := fileHandler.RemountFsReadWrite(mountPath, mountInfo.Source); remountErr != nil {
116 return fmt.Errorf("Failed to remount %s: %w", mountPath, err)
117 }
118 return nil
119 }
120
View as plain text