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  }