...

Source file src/sigs.k8s.io/kustomize/api/internal/localizer/localizer.go

Documentation: sigs.k8s.io/kustomize/api/internal/localizer

     1  // Copyright 2022 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package localizer
     5  
     6  import (
     7  	"io/fs"
     8  	"log"
     9  	"os"
    10  	"path/filepath"
    11  
    12  	"sigs.k8s.io/kustomize/api/ifc"
    13  	"sigs.k8s.io/kustomize/api/internal/generators"
    14  	"sigs.k8s.io/kustomize/api/internal/loader"
    15  	"sigs.k8s.io/kustomize/api/internal/target"
    16  	"sigs.k8s.io/kustomize/api/provider"
    17  	"sigs.k8s.io/kustomize/api/resmap"
    18  	"sigs.k8s.io/kustomize/api/types"
    19  	"sigs.k8s.io/kustomize/kyaml/errors"
    20  	"sigs.k8s.io/kustomize/kyaml/filesys"
    21  	"sigs.k8s.io/yaml"
    22  )
    23  
    24  // localizer encapsulates all state needed to localize the root at ldr.
    25  type localizer struct {
    26  	fSys filesys.FileSystem
    27  
    28  	// underlying type is Loader
    29  	ldr ifc.Loader
    30  
    31  	// root is at ldr.Root()
    32  	root filesys.ConfirmedDir
    33  
    34  	rFactory *resmap.Factory
    35  
    36  	// destination directory in newDir that mirrors root
    37  	dst string
    38  }
    39  
    40  // Run attempts to localize the kustomization root at target with the given localize arguments
    41  // and returns the path to the created newDir.
    42  func Run(target, scope, newDir string, fSys filesys.FileSystem) (string, error) {
    43  	ldr, args, err := NewLoader(target, scope, newDir, fSys)
    44  	if err != nil {
    45  		return "", errors.Wrap(err)
    46  	}
    47  	defer func() { _ = ldr.Cleanup() }()
    48  
    49  	toDst, err := filepath.Rel(args.Scope.String(), args.Target.String())
    50  	if err != nil {
    51  		log.Panicf("cannot find path from %q to child directory %q: %s", args.Scope, args.Target, err)
    52  	}
    53  	dst := args.NewDir.Join(toDst)
    54  	if err = fSys.MkdirAll(dst); err != nil {
    55  		return "", errors.WrapPrefixf(err, "unable to create directory in localize destination")
    56  	}
    57  
    58  	err = (&localizer{
    59  		fSys:     fSys,
    60  		ldr:      ldr,
    61  		root:     args.Target,
    62  		rFactory: resmap.NewFactory(provider.NewDepProvider().GetResourceFactory()),
    63  		dst:      dst,
    64  	}).localize()
    65  	if err != nil {
    66  		errCleanup := fSys.RemoveAll(args.NewDir.String())
    67  		if errCleanup != nil {
    68  			log.Printf("unable to clean localize destination: %s", errCleanup)
    69  		}
    70  		return "", errors.WrapPrefixf(err, "unable to localize target %q", target)
    71  	}
    72  	return args.NewDir.String(), nil
    73  }
    74  
    75  // localize localizes the root that lc is at
    76  func (lc *localizer) localize() error {
    77  	kustomization, kustFileName, err := lc.load()
    78  	if err != nil {
    79  		return err
    80  	}
    81  	err = lc.localizeNativeFields(kustomization)
    82  	if err != nil {
    83  		return err
    84  	}
    85  	err = lc.localizeBuiltinPlugins(kustomization)
    86  	if err != nil {
    87  		return err
    88  	}
    89  
    90  	content, err := yaml.Marshal(kustomization)
    91  	if err != nil {
    92  		return errors.WrapPrefixf(err, "unable to serialize localized kustomization file")
    93  	}
    94  	if err = lc.fSys.WriteFile(filepath.Join(lc.dst, kustFileName), content); err != nil {
    95  		return errors.WrapPrefixf(err, "unable to write localized kustomization file")
    96  	}
    97  	return nil
    98  }
    99  
   100  // load returns the kustomization at lc.root and the file name under which it was found
   101  func (lc *localizer) load() (*types.Kustomization, string, error) {
   102  	content, kustFileName, err := target.LoadKustFile(lc.ldr)
   103  	if err != nil {
   104  		return nil, "", errors.Wrap(err)
   105  	}
   106  
   107  	var kust types.Kustomization
   108  	err = (&kust).Unmarshal(content)
   109  	if err != nil {
   110  		return nil, "", errors.Wrap(err)
   111  	}
   112  
   113  	// Localize intentionally does not replace legacy fields to return a localized kustomization
   114  	// with as much resemblance to the original as possible.
   115  	// Localize also intentionally does not enforce fields, as localize does not wish to unnecessarily
   116  	// repeat the responsibilities of kustomize build.
   117  
   118  	return &kust, kustFileName, nil
   119  }
   120  
   121  // localizeNativeFields localizes paths on kustomize-native fields, like configMapGenerator, that kustomize has a
   122  // built-in understanding of. This excludes helm-related fields, such as `helmGlobals` and `helmCharts`.
   123  func (lc *localizer) localizeNativeFields(kust *types.Kustomization) error {
   124  	if path, exists := kust.OpenAPI["path"]; exists {
   125  		locPath, err := lc.localizeFile(path)
   126  		if err != nil {
   127  			return errors.WrapPrefixf(err, "unable to localize openapi path")
   128  		}
   129  		kust.OpenAPI["path"] = locPath
   130  	}
   131  
   132  	for fieldName, field := range map[string]struct {
   133  		paths []string
   134  		locFn func(string) (string, error)
   135  	}{
   136  		"bases": {
   137  			// Allow use of deprecated field
   138  			//nolint:staticcheck
   139  			kust.Bases,
   140  			lc.localizeRoot,
   141  		},
   142  		"components": {
   143  			kust.Components,
   144  			lc.localizeRoot,
   145  		},
   146  		"configurations": {
   147  			kust.Configurations,
   148  			lc.localizeFile,
   149  		},
   150  		"crds": {
   151  			kust.Crds,
   152  			lc.localizeFile,
   153  		},
   154  		"resources": {
   155  			kust.Resources,
   156  			lc.localizeResource,
   157  		},
   158  	} {
   159  		for i, path := range field.paths {
   160  			locPath, err := field.locFn(path)
   161  			if err != nil {
   162  				return errors.WrapPrefixf(err, "unable to localize %s entry", fieldName)
   163  			}
   164  			field.paths[i] = locPath
   165  		}
   166  	}
   167  
   168  	for i := range kust.ConfigMapGenerator {
   169  		if err := lc.localizeGenerator(&kust.ConfigMapGenerator[i].GeneratorArgs); err != nil {
   170  			return errors.WrapPrefixf(err, "unable to localize configMapGenerator")
   171  		}
   172  	}
   173  	for i := range kust.SecretGenerator {
   174  		if err := lc.localizeGenerator(&kust.SecretGenerator[i].GeneratorArgs); err != nil {
   175  			return errors.WrapPrefixf(err, "unable to localize secretGenerator")
   176  		}
   177  	}
   178  	if err := lc.localizeHelmInflationGenerator(kust); err != nil {
   179  		return err
   180  	}
   181  	if err := lc.localizeHelmCharts(kust); err != nil {
   182  		return err
   183  	}
   184  	if err := lc.localizePatches(kust.Patches); err != nil {
   185  		return errors.WrapPrefixf(err, "unable to localize patches")
   186  	}
   187  	//nolint:staticcheck
   188  	if err := lc.localizePatches(kust.PatchesJson6902); err != nil {
   189  		return errors.WrapPrefixf(err, "unable to localize patchesJson6902")
   190  	}
   191  	//nolint:staticcheck
   192  	for i, patch := range kust.PatchesStrategicMerge {
   193  		locPath, err := lc.localizeK8sResource(string(patch))
   194  		if err != nil {
   195  			return errors.WrapPrefixf(err, "unable to localize patchesStrategicMerge entry")
   196  		}
   197  		kust.PatchesStrategicMerge[i] = types.PatchStrategicMerge(locPath)
   198  	}
   199  	for i, replacement := range kust.Replacements {
   200  		locPath, err := lc.localizeFile(replacement.Path)
   201  		if err != nil {
   202  			return errors.WrapPrefixf(err, "unable to localize replacements entry")
   203  		}
   204  		kust.Replacements[i].Path = locPath
   205  	}
   206  	return nil
   207  }
   208  
   209  // localizeGenerator localizes the file paths on generator.
   210  func (lc *localizer) localizeGenerator(generator *types.GeneratorArgs) error {
   211  	locEnvSrc, err := lc.localizeFile(generator.EnvSource)
   212  	if err != nil {
   213  		return errors.WrapPrefixf(err, "unable to localize generator env file")
   214  	}
   215  	locEnvs := make([]string, len(generator.EnvSources))
   216  	for i, env := range generator.EnvSources {
   217  		locEnvs[i], err = lc.localizeFile(env)
   218  		if err != nil {
   219  			return errors.WrapPrefixf(err, "unable to localize generator envs file")
   220  		}
   221  	}
   222  	locFiles := make([]string, len(generator.FileSources))
   223  	for i, file := range generator.FileSources {
   224  		locFiles[i], err = lc.localizeFileSource(file)
   225  		if err != nil {
   226  			return err
   227  		}
   228  	}
   229  	generator.EnvSource = locEnvSrc
   230  	generator.EnvSources = locEnvs
   231  	generator.FileSources = locFiles
   232  	return nil
   233  }
   234  
   235  // localizeFileSource returns the localized file source found in configMap and
   236  // secretGenerators.
   237  func (lc *localizer) localizeFileSource(source string) (string, error) {
   238  	key, file, err := generators.ParseFileSource(source)
   239  	if err != nil {
   240  		return "", errors.Wrap(err)
   241  	}
   242  	locFile, err := lc.localizeFile(file)
   243  	if err != nil {
   244  		return "", errors.WrapPrefixf(err, "invalid file source %q", source)
   245  	}
   246  	var locSource string
   247  	if source == file {
   248  		locSource = locFile
   249  	} else {
   250  		locSource = key + "=" + locFile
   251  	}
   252  	return locSource, nil
   253  }
   254  
   255  // localizeHelmInflationGenerator localizes helmChartInflationGenerator on kust.
   256  // localizeHelmInflationGenerator localizes values files and copies local chart homes.
   257  func (lc *localizer) localizeHelmInflationGenerator(kust *types.Kustomization) error {
   258  	for i, chart := range kust.HelmChartInflationGenerator {
   259  		locFile, err := lc.localizeFile(chart.Values)
   260  		if err != nil {
   261  			return errors.WrapPrefixf(err, "unable to localize helmChartInflationGenerator entry %d values", i)
   262  		}
   263  		kust.HelmChartInflationGenerator[i].Values = locFile
   264  
   265  		locDir, err := lc.copyChartHomeEntry(chart.ChartHome)
   266  		if err != nil {
   267  			return errors.WrapPrefixf(err, "unable to copy helmChartInflationGenerator entry %d", i)
   268  		}
   269  		kust.HelmChartInflationGenerator[i].ChartHome = locDir
   270  	}
   271  	return nil
   272  }
   273  
   274  // localizeHelmCharts localizes helmCharts and helmGlobals on kust.
   275  // localizeHelmCharts localizes values files and copies a local chart home.
   276  func (lc *localizer) localizeHelmCharts(kust *types.Kustomization) error {
   277  	for i, chart := range kust.HelmCharts {
   278  		locFile, err := lc.localizeFile(chart.ValuesFile)
   279  		if err != nil {
   280  			return errors.WrapPrefixf(err, "unable to localize helmCharts entry %d valuesFile", i)
   281  		}
   282  		kust.HelmCharts[i].ValuesFile = locFile
   283  
   284  		for j, valuesFile := range chart.AdditionalValuesFiles {
   285  			locFile, err = lc.localizeFile(valuesFile)
   286  			if err != nil {
   287  				return errors.WrapPrefixf(err, "unable to localize helmCharts entry %d additionalValuesFiles", i)
   288  			}
   289  			kust.HelmCharts[i].AdditionalValuesFiles[j] = locFile
   290  		}
   291  	}
   292  	if kust.HelmGlobals != nil {
   293  		locDir, err := lc.copyChartHomeEntry(kust.HelmGlobals.ChartHome)
   294  		if err != nil {
   295  			return errors.WrapPrefixf(err, "unable to copy helmGlobals")
   296  		}
   297  		kust.HelmGlobals.ChartHome = locDir
   298  	} else if len(kust.HelmCharts) > 0 {
   299  		_, err := lc.copyChartHomeEntry("")
   300  		if err != nil {
   301  			return errors.WrapPrefixf(err, "unable to copy default chart home")
   302  		}
   303  	}
   304  	return nil
   305  }
   306  
   307  // localizePatches localizes the file paths on patches if they are non-empty
   308  func (lc *localizer) localizePatches(patches []types.Patch) error {
   309  	for i := range patches {
   310  		locPath, err := lc.localizeFile(patches[i].Path)
   311  		if err != nil {
   312  			return err
   313  		}
   314  		patches[i].Path = locPath
   315  	}
   316  	return nil
   317  }
   318  
   319  // localizeResource localizes resource path, a file or root, and returns the
   320  // localized path
   321  func (lc *localizer) localizeResource(path string) (string, error) {
   322  	var locPath string
   323  
   324  	content, fileErr := lc.ldr.Load(path)
   325  	// The following check catches the case where path is a repo root.
   326  	// Load on a repo will successfully return its README in HTML.
   327  	// Because HTML does not follow resource formatting, we then correctly try
   328  	// to localize path as a root.
   329  	if fileErr == nil {
   330  		_, resErr := lc.rFactory.NewResMapFromBytes(content)
   331  		if resErr != nil {
   332  			fileErr = errors.WrapPrefixf(resErr, "invalid resource at file %q", path)
   333  		} else {
   334  			locPath, fileErr = lc.localizeFileWithContent(path, content)
   335  		}
   336  	}
   337  	if fileErr != nil {
   338  		var rootErr error
   339  		locPath, rootErr = lc.localizeRoot(path)
   340  		if rootErr != nil {
   341  			err := PathLocalizeError{
   342  				Path:      path,
   343  				FileError: fileErr,
   344  				RootError: rootErr,
   345  			}
   346  			return "", err
   347  		}
   348  	}
   349  	return locPath, nil
   350  }
   351  
   352  // localizeFile localizes file path if set and returns the localized path
   353  func (lc *localizer) localizeFile(path string) (string, error) {
   354  	// Some localizable fields can be empty, for example, replacements.path.
   355  	// We rely on the build command to throw errors for the ones that cannot.
   356  	if path == "" {
   357  		return "", nil
   358  	}
   359  	content, err := lc.ldr.Load(path)
   360  	if err != nil {
   361  		return "", errors.Wrap(err)
   362  	}
   363  	return lc.localizeFileWithContent(path, content)
   364  }
   365  
   366  // localizeFileWithContent writes content to the localized file path and returns the localized path.
   367  func (lc *localizer) localizeFileWithContent(path string, content []byte) (string, error) {
   368  	var locPath string
   369  	if loader.IsRemoteFile(path) {
   370  		if lc.fSys.Exists(lc.root.Join(LocalizeDir)) {
   371  			return "", errors.Errorf("%s already contains %s needed to store file %q", lc.root, LocalizeDir, path)
   372  		}
   373  		locPath = locFilePath(path)
   374  	} else {
   375  		// ldr has checked that path must be relative; this is subject to change in beta.
   376  
   377  		// We must clean path to:
   378  		// 1. avoid symlinks. A `kustomize build` run will fail if we write files to
   379  		//    symlink paths outside the current root, given that we don't want to recreate
   380  		//    the symlinks. Even worse, we could be writing files outside the localize destination.
   381  		// 2. avoid paths that temporarily traverse outside the current root,
   382  		//    i.e. ../../../scope/target/current-root. The localized file will be surrounded by
   383  		//    different directories than its source, and so an uncleaned path may no longer be valid.
   384  		locPath = cleanFilePath(lc.fSys, lc.root, path)
   385  	}
   386  	absPath := filepath.Join(lc.dst, locPath)
   387  	if err := lc.fSys.MkdirAll(filepath.Dir(absPath)); err != nil {
   388  		return "", errors.WrapPrefixf(err, "unable to create directories to localize file %q", path)
   389  	}
   390  	if err := lc.fSys.WriteFile(absPath, content); err != nil {
   391  		return "", errors.WrapPrefixf(err, "unable to localize file %q", path)
   392  	}
   393  	return locPath, nil
   394  }
   395  
   396  // localizeRoot localizes root path if set and returns the localized path
   397  func (lc *localizer) localizeRoot(path string) (string, error) {
   398  	if path == "" {
   399  		return "", nil
   400  	}
   401  	ldr, err := lc.ldr.New(path)
   402  	if err != nil {
   403  		return "", errors.Wrap(err)
   404  	}
   405  	defer func() { _ = ldr.Cleanup() }()
   406  
   407  	root, err := filesys.ConfirmDir(lc.fSys, ldr.Root())
   408  	if err != nil {
   409  		log.Panicf("unable to establish validated root reference %q: %s", path, err)
   410  	}
   411  	var locPath string
   412  	if repo := ldr.Repo(); repo != "" {
   413  		if lc.fSys.Exists(lc.root.Join(LocalizeDir)) {
   414  			return "", errors.Errorf("%s already contains %s needed to store root %q", lc.root, LocalizeDir, path)
   415  		}
   416  		locPath, err = locRootPath(path, repo, root, lc.fSys)
   417  		if err != nil {
   418  			return "", err
   419  		}
   420  	} else {
   421  		locPath, err = filepath.Rel(lc.root.String(), root.String())
   422  		if err != nil {
   423  			log.Panicf("cannot find relative path between scoped localize roots %q and %q: %s", lc.root, root, err)
   424  		}
   425  	}
   426  	newDst := filepath.Join(lc.dst, locPath)
   427  	if err = lc.fSys.MkdirAll(newDst); err != nil {
   428  		return "", errors.WrapPrefixf(err, "unable to create root %q in localize destination", path)
   429  	}
   430  	err = (&localizer{
   431  		fSys:     lc.fSys,
   432  		ldr:      ldr,
   433  		root:     root,
   434  		rFactory: lc.rFactory,
   435  		dst:      newDst,
   436  	}).localize()
   437  	if err != nil {
   438  		return "", errors.WrapPrefixf(err, "unable to localize root %q", path)
   439  	}
   440  	return locPath, nil
   441  }
   442  
   443  // copyChartHomeEntry copies the helm chart home entry to lc dst
   444  // at the same location relative to the root and returns said relative path.
   445  // If entry is empty, copyChartHomeEntry returns the empty string.
   446  // If entry does not exist, copyChartHome returns entry.
   447  //
   448  // copyChartHomeEntry copies the default home to the same location at dst,
   449  // without following symlinks. An empty entry also indicates the default home.
   450  func (lc *localizer) copyChartHomeEntry(entry string) (string, error) {
   451  	path := entry
   452  	if entry == "" {
   453  		path = types.HelmDefaultHome
   454  	}
   455  	if filepath.IsAbs(path) {
   456  		return "", errors.Errorf("absolute path %q not handled in alpha", path)
   457  	}
   458  	isDefault := lc.root.Join(path) == lc.root.Join(types.HelmDefaultHome)
   459  	locPath, err := lc.copyChartHome(path, !isDefault)
   460  	if err != nil {
   461  		return "", errors.WrapPrefixf(err, "unable to copy home %q", entry)
   462  	}
   463  	if entry == "" {
   464  		return "", nil
   465  	}
   466  	return locPath, nil
   467  }
   468  
   469  // copyChartHome copies path relative to lc root to dst and returns the
   470  // copied location relative to dst. If clean is true, copyChartHome uses path's
   471  // delinked location as the copy destination.
   472  //
   473  // If path does not exist, copyChartHome returns path.
   474  func (lc *localizer) copyChartHome(path string, clean bool) (string, error) {
   475  	path, err := filepath.Rel(lc.root.String(), lc.root.Join(path))
   476  	if err != nil {
   477  		return "", errors.WrapPrefixf(err, "no path to chart home %q", path)
   478  	}
   479  	// Chart home may serve as untar destination.
   480  	// Note that we don't check if path is in scope.
   481  	if !lc.fSys.Exists(lc.root.Join(path)) {
   482  		return path, nil
   483  	}
   484  	// Perform localize directory checks.
   485  	ldr, err := lc.ldr.New(path)
   486  	if err != nil {
   487  		return "", errors.WrapPrefixf(err, "invalid chart home")
   488  	}
   489  	cleaned, err := filesys.ConfirmDir(lc.fSys, ldr.Root())
   490  	if err != nil {
   491  		log.Panicf("unable to confirm validated directory %q: %s", ldr.Root(), err)
   492  	}
   493  	toDst := path
   494  	if clean {
   495  		toDst, err = filepath.Rel(lc.root.String(), cleaned.String())
   496  		if err != nil {
   497  			log.Panicf("no path between scoped directories %q and %q: %s", lc.root, cleaned, err)
   498  		}
   499  	}
   500  	// Note this check does not guarantee that we copied the entire directory.
   501  	if dst := filepath.Join(lc.dst, toDst); !lc.fSys.Exists(dst) {
   502  		err = lc.copyDir(cleaned, filepath.Join(lc.dst, toDst))
   503  		if err != nil {
   504  			return "", errors.WrapPrefixf(err, "unable to copy chart home %q", path)
   505  		}
   506  	}
   507  	return toDst, nil
   508  }
   509  
   510  // copyDir copies src to dst. copyDir does not follow symlinks.
   511  func (lc *localizer) copyDir(src filesys.ConfirmedDir, dst string) error {
   512  	err := lc.fSys.Walk(src.String(),
   513  		func(path string, info fs.FileInfo, err error) error {
   514  			if err != nil {
   515  				return err
   516  			}
   517  			pathToCreate, err := filepath.Rel(src.String(), path)
   518  			if err != nil {
   519  				log.Panicf("no path from %q to child file %q: %s", src, path, err)
   520  			}
   521  			pathInDst := filepath.Join(dst, pathToCreate)
   522  			if info.Mode()&os.ModeSymlink == os.ModeSymlink {
   523  				return nil
   524  			}
   525  			if info.IsDir() {
   526  				err = lc.fSys.MkdirAll(pathInDst)
   527  			} else {
   528  				var content []byte
   529  				content, err = lc.fSys.ReadFile(path)
   530  				if err != nil {
   531  					return errors.Wrap(err)
   532  				}
   533  				err = lc.fSys.WriteFile(pathInDst, content)
   534  			}
   535  			return errors.Wrap(err)
   536  		})
   537  	if err != nil {
   538  		return errors.WrapPrefixf(err, "unable to copy directory %q", src)
   539  	}
   540  	return nil
   541  }
   542  
   543  // localizeBuiltinPlugins localizes built-in plugins on kust that can contain file paths. The built-in plugins
   544  // can be inline or in a file. This excludes the HelmChartInflationGenerator.
   545  //
   546  // Note that the localization in this function has not been implemented yet.
   547  func (lc *localizer) localizeBuiltinPlugins(kust *types.Kustomization) error {
   548  	for fieldName, entries := range map[string][]string{
   549  		"generators":   kust.Generators,
   550  		"transformers": kust.Transformers,
   551  		"validators":   kust.Validators,
   552  	} {
   553  		for i, entry := range entries {
   554  			rm, isPath, err := lc.loadK8sResource(entry)
   555  			if err != nil {
   556  				return errors.WrapPrefixf(err, "unable to load %s entry", fieldName)
   557  			}
   558  			err = rm.ApplyFilter(&localizeBuiltinPlugins{lc: lc})
   559  			if err != nil {
   560  				return errors.Wrap(err)
   561  			}
   562  			localizedPlugin, err := rm.AsYaml()
   563  			if err != nil {
   564  				return errors.WrapPrefixf(err, "unable to serialize localized %s entry %q", fieldName, entry)
   565  			}
   566  			var localizedEntry string
   567  			if isPath {
   568  				localizedEntry, err = lc.localizeFileWithContent(entry, localizedPlugin)
   569  				if err != nil {
   570  					return errors.WrapPrefixf(err, "unable to localize %s entry", fieldName)
   571  				}
   572  			} else {
   573  				localizedEntry = string(localizedPlugin)
   574  			}
   575  			entries[i] = localizedEntry
   576  		}
   577  	}
   578  	return nil
   579  }
   580  
   581  // localizeK8sResource returns the localized resourceEntry if it is a file
   582  // containing a kubernetes resource.
   583  // localizeK8sResource returns resourceEntry if it is an inline resource.
   584  func (lc *localizer) localizeK8sResource(resourceEntry string) (string, error) {
   585  	_, isFile, err := lc.loadK8sResource(resourceEntry)
   586  	if err != nil {
   587  		return "", err
   588  	}
   589  	if isFile {
   590  		return lc.localizeFile(resourceEntry)
   591  	}
   592  	return resourceEntry, nil
   593  }
   594  
   595  // loadK8sResource tries to load resourceEntry as a file path or inline
   596  // kubernetes resource.
   597  // On success, loadK8sResource returns the loaded resource map and whether
   598  // resourceEntry is a file path.
   599  func (lc *localizer) loadK8sResource(resourceEntry string) (resmap.ResMap, bool, error) {
   600  	rm, inlineErr := lc.rFactory.NewResMapFromBytes([]byte(resourceEntry))
   601  	if inlineErr != nil {
   602  		var fileErr error
   603  		rm, fileErr = lc.rFactory.FromFile(lc.ldr, resourceEntry)
   604  		if fileErr != nil {
   605  			err := ResourceLoadError{
   606  				InlineError: inlineErr,
   607  				FileError:   fileErr,
   608  			}
   609  			return nil, false, errors.WrapPrefixf(err, "unable to load resource entry %q", resourceEntry)
   610  		}
   611  	}
   612  	return rm, inlineErr != nil, nil
   613  }
   614  

View as plain text