...

Source file src/sigs.k8s.io/kustomize/api/krusty/kustomizer.go

Documentation: sigs.k8s.io/kustomize/api/krusty

     1  // Copyright 2019 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package krusty
     5  
     6  import (
     7  	"fmt"
     8  	"log"
     9  
    10  	"sigs.k8s.io/kustomize/api/internal/builtins"
    11  	fLdr "sigs.k8s.io/kustomize/api/internal/loader"
    12  	pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
    13  	"sigs.k8s.io/kustomize/api/internal/target"
    14  	"sigs.k8s.io/kustomize/api/internal/utils"
    15  	"sigs.k8s.io/kustomize/api/konfig"
    16  	"sigs.k8s.io/kustomize/api/provenance"
    17  	"sigs.k8s.io/kustomize/api/provider"
    18  	"sigs.k8s.io/kustomize/api/resmap"
    19  	"sigs.k8s.io/kustomize/api/types"
    20  	"sigs.k8s.io/kustomize/kyaml/errors"
    21  	"sigs.k8s.io/kustomize/kyaml/filesys"
    22  	"sigs.k8s.io/kustomize/kyaml/openapi"
    23  )
    24  
    25  // Kustomizer performs kustomizations.
    26  //
    27  // It's meant to behave similarly to the kustomize CLI, and can be
    28  // used instead of performing an exec to a kustomize CLI subprocess.
    29  // To use, load a filesystem with kustomization files (any
    30  // number of overlays and bases), then make a Kustomizer
    31  // injected with the given filesystem, then call Run.
    32  type Kustomizer struct {
    33  	options     *Options
    34  	depProvider *provider.DepProvider
    35  }
    36  
    37  // MakeKustomizer returns an instance of Kustomizer.
    38  func MakeKustomizer(o *Options) *Kustomizer {
    39  	return &Kustomizer{
    40  		options:     o,
    41  		depProvider: provider.NewDepProvider(),
    42  	}
    43  }
    44  
    45  // Run performs a kustomization.
    46  //
    47  // It reads given path from the given file system, interprets it as
    48  // a kustomization.yaml file, perform the kustomization it represents,
    49  // and return the resulting resources.
    50  //
    51  // Any files referenced by the kustomization must be present on the
    52  // filesystem.  One may call Run any number of times, on any number
    53  // of internal paths (e.g. the filesystem may contain multiple overlays,
    54  // and Run can be called on each of them).
    55  func (b *Kustomizer) Run(
    56  	fSys filesys.FileSystem, path string) (resmap.ResMap, error) {
    57  	resmapFactory := resmap.NewFactory(b.depProvider.GetResourceFactory())
    58  	lr := fLdr.RestrictionNone
    59  	if b.options.LoadRestrictions == types.LoadRestrictionsRootOnly {
    60  		lr = fLdr.RestrictionRootOnly
    61  	}
    62  	ldr, err := fLdr.NewLoader(lr, path, fSys)
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  	defer ldr.Cleanup()
    67  	kt := target.NewKustTarget(
    68  		ldr,
    69  		b.depProvider.GetFieldValidator(),
    70  		resmapFactory,
    71  		// The plugin configs are always located on disk, regardless of the fSys passed in
    72  		pLdr.NewLoader(b.options.PluginConfig, resmapFactory, filesys.MakeFsOnDisk()),
    73  	)
    74  	err = kt.Load()
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  	var bytes []byte
    79  	if openApiPath, exists := kt.Kustomization().OpenAPI["path"]; exists {
    80  		bytes, err = ldr.Load(openApiPath)
    81  		if err != nil {
    82  			return nil, err
    83  		}
    84  	}
    85  	err = openapi.SetSchema(kt.Kustomization().OpenAPI, bytes, true)
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  	var m resmap.ResMap
    90  	m, err = kt.MakeCustomizedResMap()
    91  	if err != nil {
    92  		return nil, err
    93  	}
    94  	err = b.applySortOrder(m, kt)
    95  	if err != nil {
    96  		return nil, err
    97  	}
    98  	if b.options.AddManagedbyLabel || utils.StringSliceContains(kt.Kustomization().BuildMetadata, types.ManagedByLabelOption) {
    99  		t := builtins.LabelTransformerPlugin{
   100  			Labels: map[string]string{
   101  				konfig.ManagedbyLabelKey: fmt.Sprintf("kustomize-%s", provenance.GetProvenance().Semver()),
   102  			},
   103  			FieldSpecs: []types.FieldSpec{{
   104  				Path:               "metadata/labels",
   105  				CreateIfNotPresent: true,
   106  			}},
   107  		}
   108  		err = t.Transform(m)
   109  		if err != nil {
   110  			return nil, err
   111  		}
   112  	}
   113  	m.RemoveBuildAnnotations()
   114  	if !utils.StringSliceContains(kt.Kustomization().BuildMetadata, types.OriginAnnotations) {
   115  		err = m.RemoveOriginAnnotations()
   116  		if err != nil {
   117  			return nil, errors.WrapPrefixf(err, "failed to clean up origin tracking annotations")
   118  		}
   119  	}
   120  	if !utils.StringSliceContains(kt.Kustomization().BuildMetadata, types.TransformerAnnotations) {
   121  		err = m.RemoveTransformerAnnotations()
   122  		if err != nil {
   123  			return nil, errors.WrapPrefixf(err, "failed to clean up transformer annotations")
   124  		}
   125  	}
   126  	return m, nil
   127  }
   128  
   129  func (b *Kustomizer) applySortOrder(m resmap.ResMap, kt *target.KustTarget) error {
   130  	// Sort order can be defined in two places:
   131  	// - (new) kustomization file
   132  	// - (old) CLI flag
   133  	//
   134  	// We want the kustomization file to take precedence over the CLI flag.
   135  	// Eventually, we may want to move away from having a CLI flag altogether:
   136  	// https://github.com/kubernetes-sigs/kustomize/issues/3947
   137  
   138  	// Case 1: Sort order set in kustomization file.
   139  	if kt.Kustomization().SortOptions != nil {
   140  		// If set in CLI flag too, warn the user.
   141  		if b.options.Reorder != ReorderOptionUnspecified {
   142  			log.Println("Warning: Sorting order is set both in 'kustomization.yaml'" +
   143  				" ('sortOptions') and in a CLI flag ('--reorder'). Using the" +
   144  				" kustomization file over the CLI flag.")
   145  		}
   146  		pl := &builtins.SortOrderTransformerPlugin{
   147  			SortOptions: kt.Kustomization().SortOptions,
   148  		}
   149  		err := pl.Transform(m)
   150  		if err != nil {
   151  			return errors.Wrap(err)
   152  		}
   153  	} else if b.options.Reorder == ReorderOptionLegacy || b.options.Reorder == ReorderOptionUnspecified {
   154  		// Case 2: Sort order set in CLI flag only or not at all.
   155  		pl := &builtins.SortOrderTransformerPlugin{
   156  			SortOptions: &types.SortOptions{
   157  				Order: types.LegacySortOrder,
   158  			},
   159  		}
   160  		return errors.Wrap(pl.Transform(m))
   161  	}
   162  	return nil
   163  }
   164  

View as plain text