github.com/replicatedhq/ship@v0.55.0/pkg/lifecycle/kustomize/daemonless.go (about) 1 package kustomize 2 3 import ( 4 "context" 5 "path/filepath" 6 "strings" 7 8 "github.com/go-kit/kit/log" 9 "github.com/go-kit/kit/log/level" 10 "github.com/pkg/errors" 11 "github.com/spf13/afero" 12 "github.com/spf13/viper" 13 yaml "gopkg.in/yaml.v3" 14 15 "github.com/replicatedhq/ship/pkg/api" 16 "github.com/replicatedhq/ship/pkg/constants" 17 "github.com/replicatedhq/ship/pkg/lifecycle" 18 "github.com/replicatedhq/ship/pkg/patch" 19 "github.com/replicatedhq/ship/pkg/state" 20 "github.com/replicatedhq/ship/pkg/util" 21 ) 22 23 type Kustomizer struct { 24 Logger log.Logger 25 FS afero.Afero 26 State state.Manager 27 Patcher patch.ShipPatcher 28 Viper *viper.Viper 29 renderedUpstream string 30 } 31 32 func NewDaemonlessKustomizer( 33 logger log.Logger, 34 fs afero.Afero, 35 state state.Manager, 36 viper *viper.Viper, 37 ) lifecycle.Kustomizer { 38 return &Kustomizer{ 39 Logger: logger, 40 FS: fs, 41 State: state, 42 Viper: viper, 43 } 44 } 45 46 func (l *Kustomizer) Execute(ctx context.Context, release *api.Release, step api.Kustomize) error { 47 debug := level.Debug(log.With(l.Logger, "struct", "daemonless.kustomizer", "method", "execute")) 48 49 current, err := l.State.CachedState() 50 if err != nil { 51 return errors.Wrap(err, "load state") 52 } 53 54 debug.Log("event", "state.loaded") 55 kustomizeState := current.CurrentKustomize() 56 57 var shipOverlay state.Overlay 58 if kustomizeState == nil { 59 debug.Log("event", "state.kustomize.empty") 60 } else { 61 shipOverlay = kustomizeState.Ship() 62 } 63 64 debug.Log("event", "base.kustomization.check") 65 existingKustomize, err := l.FS.Exists(filepath.Join(step.Base, "kustomization.yaml")) 66 if err != nil { 67 return errors.Wrapf(err, "check for kustomization in %s", step.Base) 68 } 69 if existingKustomize { 70 // no need to write base, kustomization already exists 71 // but we do need to remove excluded bases 72 debug.Log("event", "exclude.kustomize.resources") 73 err = util.ExcludeKubernetesResources(l.FS, step.Base, constants.DefaultOverlaysPath, shipOverlay.ExcludedBases) 74 if err != nil { 75 return errors.Wrapf(err, "write base %s", step.Base) 76 } 77 } else { 78 debug.Log("event", "write.base.kustomization.yaml") 79 err = l.writeBase(step.Base) 80 if err != nil { 81 return errors.Wrap(err, "write base kustomization") 82 } 83 } 84 85 fs, err := l.getPotentiallyChrootedFs(release) 86 if err != nil { 87 debug.Log("event", "getFs.fail") 88 return errors.Wrapf(err, "get base fs") 89 } 90 91 debug.Log("event", "mkdir", "dir", step.OverlayPath()) 92 err = l.FS.MkdirAll(step.OverlayPath(), 0777) 93 if err != nil { 94 debug.Log("event", "mkdir.fail", "dir", step.OverlayPath()) 95 return errors.Wrapf(err, "make dir %s", step.OverlayPath()) 96 } 97 98 relativePatchPaths, err := l.writePatches(fs, shipOverlay, step.OverlayPath()) 99 if err != nil { 100 return err 101 } 102 103 relativeResourcePaths, err := l.writeResources(fs, shipOverlay, step.OverlayPath()) 104 if err != nil { 105 return err 106 } 107 108 err = l.writeOverlay(step, relativePatchPaths, relativeResourcePaths, shipOverlay.RawKustomize) 109 if err != nil { 110 return errors.Wrap(err, "write overlay") 111 } 112 113 if step.Dest != "" { 114 debug.Log("event", "kustomize.build", "dest", step.Dest) 115 built, err := l.kustomizeBuild(step.OverlayPath()) 116 if err != nil { 117 return errors.Wrap(err, "build overlay") 118 } 119 120 if err := l.writePostKustomizeFiles(step, built); err != nil { 121 return errors.Wrapf(err, "write kustomized and post processed yaml at %s", step.Dest) 122 } 123 } 124 125 err = l.maybeCleanupKustomizeState() 126 if err != nil { 127 return errors.Wrapf(err, "maybe cleanup kustomize state") 128 } 129 130 return nil 131 } 132 133 func (l *Kustomizer) kustomizeBuild(kustomizePath string) ([]util.PostKustomizeFile, error) { 134 debug := level.Debug(log.With(l.Logger, "struct", "daemonless.kustomizer", "method", "kustomizeBuild")) 135 136 builtYAML, err := l.Patcher.RunKustomize(kustomizePath) 137 if err != nil { 138 return nil, errors.Wrap(err, "run kustomize") 139 } 140 141 files := strings.Split(string(builtYAML), "\n---\n") 142 postKustomizeFiles := make([]util.PostKustomizeFile, 0) 143 for idx, file := range files { 144 var fullYaml interface{} 145 146 debug.Log("event", "unmarshal part of rendered") 147 if err := yaml.Unmarshal([]byte(file), &fullYaml); err != nil { 148 return postKustomizeFiles, errors.Wrap(err, "unmarshal part of rendered") 149 } 150 151 debug.Log("event", "unmarshal part of rendered to minimal") 152 minimal := util.MinimalK8sYaml{} 153 if err := yaml.Unmarshal([]byte(file), &minimal); err != nil { 154 return postKustomizeFiles, errors.Wrap(err, "unmarshal part of rendered to minimal") 155 } 156 157 postKustomizeFiles = append(postKustomizeFiles, util.PostKustomizeFile{ 158 Order: idx, 159 Minimal: minimal, 160 Full: fullYaml, 161 }) 162 } 163 164 return postKustomizeFiles, nil 165 }