github.com/replicatedhq/ship@v0.55.0/pkg/lifecycle/render/inline/render.go (about)

     1  package inline
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"path/filepath"
     7  
     8  	"github.com/go-kit/kit/log"
     9  	"github.com/go-kit/kit/log/level"
    10  	"github.com/pkg/errors"
    11  	"github.com/replicatedhq/libyaml"
    12  	"github.com/replicatedhq/ship/pkg/api"
    13  	"github.com/replicatedhq/ship/pkg/lifecycle/render/root"
    14  	"github.com/replicatedhq/ship/pkg/templates"
    15  	"github.com/replicatedhq/ship/pkg/util"
    16  	"github.com/spf13/viper"
    17  )
    18  
    19  // Renderer is something that can render a helm asset as part of a planner.Plan
    20  type Renderer interface {
    21  	Execute(
    22  		rootFs root.Fs,
    23  		asset api.InlineAsset,
    24  		meta api.ReleaseMetadata,
    25  		templateContext map[string]interface{},
    26  		configGroups []libyaml.ConfigGroup,
    27  	) func(ctx context.Context) error
    28  }
    29  
    30  var _ Renderer = &LocalRenderer{}
    31  
    32  // LocalRenderer can add a helm step to the plan, the step will fetch the
    33  // chart to a temporary location and then run a local operation to run the helm templating
    34  type LocalRenderer struct {
    35  	Logger         log.Logger
    36  	BuilderBuilder *templates.BuilderBuilder
    37  	Viper          *viper.Viper
    38  }
    39  
    40  func NewRenderer(
    41  	logger log.Logger,
    42  	bb *templates.BuilderBuilder,
    43  	v *viper.Viper,
    44  ) Renderer {
    45  	return &LocalRenderer{
    46  		Logger:         logger,
    47  		BuilderBuilder: bb,
    48  		Viper:          v,
    49  	}
    50  }
    51  
    52  func (r *LocalRenderer) Execute(
    53  	rootFs root.Fs,
    54  	asset api.InlineAsset,
    55  	meta api.ReleaseMetadata,
    56  	templateContext map[string]interface{},
    57  	configGroups []libyaml.ConfigGroup,
    58  ) func(ctx context.Context) error {
    59  	debug := level.Debug(log.With(r.Logger, "step.type", "render", "render.phase", "execute", "asset.type", "inline", "dest", asset.Dest, "description", asset.Description))
    60  
    61  	return func(ctx context.Context) error {
    62  		debug.Log("event", "execute")
    63  
    64  		builder, err := r.BuilderBuilder.FullBuilder(meta, configGroups, templateContext)
    65  		if err != nil {
    66  			return errors.Wrap(err, "init builder")
    67  		}
    68  
    69  		builtAsset, err := templateInline(builder, asset)
    70  		if err != nil {
    71  			return errors.Wrap(err, "building contents")
    72  		}
    73  
    74  		err = util.IsLegalPath(builtAsset.Dest)
    75  		if err != nil {
    76  			return errors.Wrap(err, "write inline asset")
    77  		}
    78  
    79  		basePath := filepath.Dir(asset.Dest)
    80  		debug.Log("event", "mkdirall.attempt", "dest", builtAsset.Dest, "basePath", basePath)
    81  		if err := rootFs.MkdirAll(basePath, 0755); err != nil {
    82  			debug.Log("event", "mkdirall.fail", "err", err, "dest", builtAsset.Dest, "basePath", basePath)
    83  			return errors.Wrapf(err, "write directory to %s", builtAsset.Dest)
    84  		}
    85  
    86  		mode := os.FileMode(0644)
    87  		if builtAsset.Mode != os.FileMode(0) {
    88  			debug.Log("event", "applying override permissions", "override.filemode", builtAsset.Mode, "override.filemode.int", int(builtAsset.Mode))
    89  			mode = builtAsset.Mode
    90  		}
    91  
    92  		if err := rootFs.WriteFile(builtAsset.Dest, []byte(builtAsset.Contents), mode); err != nil {
    93  			debug.Log("event", "execute.fail", "err", err)
    94  			return errors.Wrapf(err, "Write inline asset to %s", builtAsset.Dest)
    95  		}
    96  		if err := rootFs.Chmod(builtAsset.Dest, mode); err != nil {
    97  			debug.Log("event", "chmod.fail", "err", err)
    98  			return errors.Wrapf(err, "Set inline asset %s filemode to %s", builtAsset.Dest, mode)
    99  		}
   100  		return nil
   101  
   102  	}
   103  }
   104  
   105  func templateInline(builder *templates.Builder, asset api.InlineAsset) (api.InlineAsset, error) {
   106  	builtAsset := asset
   107  	var err error
   108  
   109  	builtAsset.Contents, err = builder.String(asset.Contents)
   110  	if err != nil {
   111  		return builtAsset, errors.Wrap(err, "building contents")
   112  	}
   113  
   114  	builtAsset.Dest, err = builder.String(asset.Dest)
   115  	if err != nil {
   116  		return builtAsset, errors.Wrap(err, "building dest")
   117  	}
   118  
   119  	return builtAsset, nil
   120  }