feat: kubesphere 4.0 (#6115)

* feat: kubesphere 4.0

Signed-off-by: ci-bot <ci-bot@kubesphere.io>

* feat: kubesphere 4.0

Signed-off-by: ci-bot <ci-bot@kubesphere.io>

---------

Signed-off-by: ci-bot <ci-bot@kubesphere.io>
Co-authored-by: ks-ci-bot <ks-ci-bot@example.com>
Co-authored-by: joyceliu <joyceliu@yunify.com>
This commit is contained in:
KubeSphere CI Bot
2024-09-06 11:05:52 +08:00
committed by GitHub
parent b5015ec7b9
commit 447a51f08b
8557 changed files with 546695 additions and 1146174 deletions

View File

@@ -7,11 +7,11 @@ import (
"encoding/json"
"strings"
"github.com/pkg/errors"
"k8s.io/kube-openapi/pkg/validation/spec"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/filesys"
"sigs.k8s.io/kustomize/kyaml/resid"
"sigs.k8s.io/yaml"
@@ -39,7 +39,7 @@ func LoadConfigFromCRDs(
}
m, err := makeNameToApiMap(content)
if err != nil {
return nil, errors.Wrapf(err, "unable to parse open API definition from '%s'", path)
return nil, errors.WrapPrefixf(err, "unable to parse open API definition from '%s'", path)
}
otherTc, err := makeConfigFromApiMap(m)
if err != nil {

View File

@@ -170,9 +170,10 @@ func (ra *ResAccumulator) FixBackReferences() (err error) {
// Intersection drops the resources which "other" does not have.
func (ra *ResAccumulator) Intersection(other resmap.ResMap) error {
otherIds := other.AllIds()
for _, curId := range ra.resMap.AllIds() {
toDelete := true
for _, otherId := range other.AllIds() {
for _, otherId := range otherIds {
if otherId == curId {
toDelete = false
break

View File

@@ -1,5 +1,5 @@
// Code generated by pluginator on AnnotationsTransformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
// pluginator {(devel) unknown }
package builtins

View File

@@ -1,5 +1,5 @@
// Code generated by pluginator on ConfigMapGenerator; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
// pluginator {(devel) unknown }
package builtins

View File

@@ -1,5 +1,5 @@
// Code generated by pluginator on HashTransformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
// pluginator {(devel) unknown }
package builtins

View File

@@ -1,12 +1,11 @@
// Code generated by pluginator on HelmChartInflationGenerator; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
// pluginator {(devel) unknown }
package builtins
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
@@ -14,14 +13,14 @@ import (
"strings"
"github.com/imdario/mergo"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/yaml"
)
// HelmChartInflationGeneratorPlugin is a plugin to generate resources
// from a remote or local helm chart.
// Generate resources from a remote or local helm chart.
type HelmChartInflationGeneratorPlugin struct {
h *resmap.PluginHelpers
types.HelmGlobals
@@ -29,8 +28,6 @@ type HelmChartInflationGeneratorPlugin struct {
tmpDir string
}
var KustomizePlugin HelmChartInflationGeneratorPlugin
const (
valuesMergeOptionMerge = "merge"
valuesMergeOptionOverride = "override"
@@ -73,7 +70,7 @@ func (p *HelmChartInflationGeneratorPlugin) establishTmpDir() (err error) {
// already done.
return nil
}
p.tmpDir, err = ioutil.TempDir("", "kustomize-helm-")
p.tmpDir, err = os.MkdirTemp("", "kustomize-helm-")
return err
}
@@ -87,15 +84,23 @@ func (p *HelmChartInflationGeneratorPlugin) validateArgs() (err error) {
// the loader root (unless root restrictions are
// disabled, in which case this can be an absolute path).
if p.ChartHome == "" {
p.ChartHome = "charts"
p.ChartHome = types.HelmDefaultHome
}
// The ValuesFile may be consulted by the plugin, so it must
// The ValuesFile(s) may be consulted by the plugin, so it must
// be under the loader root (unless root restrictions are
// disabled).
if p.ValuesFile == "" {
p.ValuesFile = filepath.Join(p.ChartHome, p.Name, "values.yaml")
}
for i, file := range p.AdditionalValuesFiles {
// use Load() to enforce root restrictions
if _, err := p.h.Loader().Load(file); err != nil {
return errors.WrapPrefixf(err, "could not load additionalValuesFile")
}
// the additional values filepaths must be relative to the kust root
p.AdditionalValuesFiles[i] = filepath.Join(p.h.Loader().Root(), file)
}
if err = p.errIfIllegalValuesMerge(); err != nil {
return err
@@ -104,7 +109,7 @@ func (p *HelmChartInflationGeneratorPlugin) validateArgs() (err error) {
// ConfigHome is not loaded by the plugin, and can be located anywhere.
if p.ConfigHome == "" {
if err = p.establishTmpDir(); err != nil {
return errors.Wrap(
return errors.WrapPrefixf(
err, "unable to create tmp dir for HELM_CONFIG_HOME")
}
p.ConfigHome = filepath.Join(p.tmpDir, "helm")
@@ -148,10 +153,10 @@ func (p *HelmChartInflationGeneratorPlugin) runHelmCommand(
err := cmd.Run()
if err != nil {
helm := p.h.GeneralConfig().HelmConfig.Command
err = errors.Wrap(
err = errors.WrapPrefixf(
fmt.Errorf(
"unable to run: '%s %s' with env=%s (is '%s' installed?)",
helm, strings.Join(args, " "), env, helm),
"unable to run: '%s %s' with env=%s (is '%s' installed?): %w",
helm, strings.Join(args, " "), env, helm, err),
stderr.String(),
)
}
@@ -211,7 +216,7 @@ func (p *HelmChartInflationGeneratorPlugin) writeValuesBytes(
return "", fmt.Errorf("cannot create tmp dir to write helm values")
}
path := filepath.Join(p.tmpDir, p.Name+"-kustomize-values.yaml")
return path, ioutil.WriteFile(path, b, 0644)
return path, errors.WrapPrefixf(os.WriteFile(path, b, 0644), "failed to write values file")
}
func (p *HelmChartInflationGeneratorPlugin) cleanup() {
@@ -244,46 +249,31 @@ func (p *HelmChartInflationGeneratorPlugin) Generate() (rm resmap.ResMap, err er
return nil, err
}
var stdout []byte
stdout, err = p.runHelmCommand(p.templateCommand())
stdout, err = p.runHelmCommand(p.AsHelmArgs(p.absChartHome()))
if err != nil {
return nil, err
}
rm, err = p.h.ResmapFactory().NewResMapFromBytes(stdout)
if err == nil {
rm, resMapErr := p.h.ResmapFactory().NewResMapFromBytes(stdout)
if resMapErr == nil {
return rm, nil
}
// try to remove the contents before first "---" because
// helm may produce messages to stdout before it
stdoutStr := string(stdout)
if idx := strings.Index(stdoutStr, "---"); idx != -1 {
return p.h.ResmapFactory().NewResMapFromBytes([]byte(stdoutStr[idx:]))
r := &kio.ByteReader{Reader: bytes.NewBufferString(string(stdout)), OmitReaderAnnotations: true}
nodes, err := r.Read()
if err != nil {
return nil, fmt.Errorf("error reading helm output: %w", err)
}
return nil, err
}
func (p *HelmChartInflationGeneratorPlugin) templateCommand() []string {
args := []string{"template"}
if p.ReleaseName != "" {
args = append(args, p.ReleaseName)
if len(nodes) != 0 {
rm, err = p.h.ResmapFactory().NewResMapFromRNodeSlice(nodes)
if err != nil {
return nil, fmt.Errorf("could not parse rnode slice into resource map: %w", err)
}
return rm, nil
}
if p.Namespace != "" {
args = append(args, "--namespace", p.Namespace)
}
args = append(args, filepath.Join(p.absChartHome(), p.Name))
if p.ValuesFile != "" {
args = append(args, "--values", p.ValuesFile)
}
if p.ReleaseName == "" {
// AFAICT, this doesn't work as intended due to a bug in helm.
// See https://github.com/helm/helm/issues/6019
// I've tried placing the flag before and after the name argument.
args = append(args, "--generate-name")
}
if p.IncludeCRDs {
args = append(args, "--include-crds")
}
return args
return nil, fmt.Errorf("could not parse bytes into resource map: %w", resMapErr)
}
func (p *HelmChartInflationGeneratorPlugin) pullCommand() []string {

View File

@@ -1,5 +1,5 @@
// Code generated by pluginator on IAMPolicyGenerator; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
// pluginator {(devel) unknown }
package builtins

View File

@@ -1,5 +1,5 @@
// Code generated by pluginator on ImageTagTransformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
// pluginator {(devel) unknown }
package builtins

View File

@@ -1,5 +1,5 @@
// Code generated by pluginator on LabelTransformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
// pluginator {(devel) unknown }
package builtins

View File

@@ -1,46 +0,0 @@
// Code generated by pluginator on LegacyOrderTransformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
package builtins
import (
"sort"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
)
// Sort the resources using an ordering defined in the Gvk class.
// This puts cluster-wide basic resources with no
// dependencies (like Namespace, StorageClass, etc.)
// first, and resources with a high number of dependencies
// (like ValidatingWebhookConfiguration) last.
type LegacyOrderTransformerPlugin struct{}
// Nothing needed for configuration.
func (p *LegacyOrderTransformerPlugin) Config(
_ *resmap.PluginHelpers, _ []byte) (err error) {
return nil
}
func (p *LegacyOrderTransformerPlugin) Transform(m resmap.ResMap) (err error) {
resources := make([]*resource.Resource, m.Size())
ids := m.AllIds()
sort.Sort(resmap.IdSlice(ids))
for i, id := range ids {
resources[i], err = m.GetByCurrentId(id)
if err != nil {
return errors.Wrap(err, "expected match for sorting")
}
}
m.Clear()
for _, r := range resources {
m.Append(r)
}
return nil
}
func NewLegacyOrderTransformerPlugin() resmap.TransformerPlugin {
return &LegacyOrderTransformerPlugin{}
}

View File

@@ -1,5 +1,5 @@
// Code generated by pluginator on NamespaceTransformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
// pluginator {(devel) unknown }
package builtins

View File

@@ -1,5 +1,5 @@
// Code generated by pluginator on PatchJson6902Transformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
// pluginator {(devel) unknown }
package builtins
@@ -7,11 +7,11 @@ import (
"fmt"
jsonpatch "github.com/evanphx/json-patch"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/filters/patchjson6902"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
"sigs.k8s.io/yaml"
)
@@ -61,7 +61,7 @@ func (p *PatchJson6902TransformerPlugin) Config(
}
p.decodedPatch, err = jsonpatch.DecodePatch([]byte(p.JsonOp))
if err != nil {
return errors.Wrapf(err, "decoding %s", p.JsonOp)
return errors.WrapPrefixf(err, "decoding %s", p.JsonOp)
}
if len(p.decodedPatch) == 0 {
return fmt.Errorf(

View File

@@ -1,5 +1,5 @@
// Code generated by pluginator on PatchStrategicMergeTransformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
// pluginator {(devel) unknown }
package builtins

View File

@@ -1,5 +1,5 @@
// Code generated by pluginator on PatchTransformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
// pluginator {(devel) unknown }
package builtins

View File

@@ -1,5 +1,5 @@
// Code generated by pluginator on PrefixTransformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
// pluginator {(devel) unknown }
package builtins

View File

@@ -1,5 +1,5 @@
// Code generated by pluginator on ReplacementTransformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
// pluginator {(devel) unknown }
package builtins

View File

@@ -1,5 +1,5 @@
// Code generated by pluginator on ReplicaCountTransformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
// pluginator {(devel) unknown }
package builtins

View File

@@ -1,5 +1,5 @@
// Code generated by pluginator on SecretGenerator; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
// pluginator {(devel) unknown }
package builtins

View File

@@ -0,0 +1,244 @@
// Code generated by pluginator on SortOrderTransformer; DO NOT EDIT.
// pluginator {(devel) unknown }
package builtins
import (
"sort"
"strings"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/resid"
"sigs.k8s.io/yaml"
)
// Sort the resources using a customizable ordering based of Kind.
// Defaults to the ordering of the GVK struct, which puts cluster-wide basic
// resources with no dependencies (like Namespace, StorageClass, etc.) first,
// and resources with a high number of dependencies
// (like ValidatingWebhookConfiguration) last.
type SortOrderTransformerPlugin struct {
SortOptions *types.SortOptions `json:"sortOptions,omitempty" yaml:"sortOptions,omitempty"`
}
func (p *SortOrderTransformerPlugin) Config(
_ *resmap.PluginHelpers, c []byte) error {
return errors.WrapPrefixf(yaml.Unmarshal(c, p), "Failed to unmarshal SortOrderTransformer config")
}
func (p *SortOrderTransformerPlugin) applyDefaults() {
// Default to FIFO sort, aka no-op.
if p.SortOptions == nil {
p.SortOptions = &types.SortOptions{
Order: types.FIFOSortOrder,
}
}
// If legacy sort is selected and no options are given, default to
// hardcoded order.
if p.SortOptions.Order == types.LegacySortOrder && p.SortOptions.LegacySortOptions == nil {
p.SortOptions.LegacySortOptions = &types.LegacySortOptions{
OrderFirst: defaultOrderFirst,
OrderLast: defaultOrderLast,
}
}
}
func (p *SortOrderTransformerPlugin) validate() error {
// Check valid values for SortOrder
if p.SortOptions.Order != types.FIFOSortOrder && p.SortOptions.Order != types.LegacySortOrder {
return errors.Errorf("the field 'sortOptions.order' must be one of [%s, %s]",
types.FIFOSortOrder, types.LegacySortOrder)
}
// Validate that the only options set are the ones corresponding to the
// selected sort order.
if p.SortOptions.Order == types.FIFOSortOrder &&
p.SortOptions.LegacySortOptions != nil {
return errors.Errorf("the field 'sortOptions.legacySortOptions' is"+
" set but the selected sort order is '%v', not 'legacy'",
p.SortOptions.Order)
}
return nil
}
func (p *SortOrderTransformerPlugin) Transform(m resmap.ResMap) (err error) {
p.applyDefaults()
err = p.validate()
if err != nil {
return err
}
// Sort
if p.SortOptions.Order == types.LegacySortOrder {
s := newLegacyIDSorter(m.AllIds(), p.SortOptions.LegacySortOptions)
sort.Sort(s)
err = applyOrdering(m, s.resids)
if err != nil {
return err
}
}
return nil
}
// applyOrdering takes resources (given in ResMap) and a desired ordering given
// as a sequence of ResIds, and updates the ResMap's resources to match the
// ordering.
func applyOrdering(m resmap.ResMap, ordering []resid.ResId) error {
var err error
resources := make([]*resource.Resource, m.Size())
// Clear and refill with the correct order
for i, id := range ordering {
resources[i], err = m.GetByCurrentId(id)
if err != nil {
return errors.WrapPrefixf(err, "expected match for sorting")
}
}
m.Clear()
for _, r := range resources {
err = m.Append(r)
if err != nil {
return errors.WrapPrefixf(err, "SortOrderTransformer: Failed to append to resources")
}
}
return nil
}
// Code for legacy sorting.
// Legacy sorting is a "fixed" order sorting maintained for backwards
// compatibility.
// legacyIDSorter sorts resources based on two priority lists:
// - orderFirst: Resources that should be placed in the start, in the given order.
// - orderLast: Resources that should be placed in the end, in the given order.
type legacyIDSorter struct {
// resids only stores the metadata of the object. This is an optimization as
// it's expensive to compute these again and again during ordering.
resids []resid.ResId
typeOrders map[string]int
}
func newLegacyIDSorter(
resids []resid.ResId,
options *types.LegacySortOptions) *legacyIDSorter {
// Precalculate a resource ranking based on the priority lists.
var typeOrders = func() map[string]int {
m := map[string]int{}
for i, n := range options.OrderFirst {
m[n] = -len(options.OrderFirst) + i
}
for i, n := range options.OrderLast {
m[n] = 1 + i
}
return m
}()
return &legacyIDSorter{
resids: resids,
typeOrders: typeOrders,
}
}
var _ sort.Interface = legacyIDSorter{}
func (a legacyIDSorter) Len() int { return len(a.resids) }
func (a legacyIDSorter) Swap(i, j int) {
a.resids[i], a.resids[j] = a.resids[j], a.resids[i]
}
func (a legacyIDSorter) Less(i, j int) bool {
if !a.resids[i].Gvk.Equals(a.resids[j].Gvk) {
return gvkLessThan(a.resids[i].Gvk, a.resids[j].Gvk, a.typeOrders)
}
return legacyResIDSortString(a.resids[i]) < legacyResIDSortString(a.resids[j])
}
func gvkLessThan(gvk1, gvk2 resid.Gvk, typeOrders map[string]int) bool {
index1 := typeOrders[gvk1.Kind]
index2 := typeOrders[gvk2.Kind]
if index1 != index2 {
return index1 < index2
}
return legacyGVKSortString(gvk1) < legacyGVKSortString(gvk2)
}
// legacyGVKSortString returns a string representation of given GVK used for
// stable sorting.
func legacyGVKSortString(x resid.Gvk) string {
legacyNoGroup := "~G"
legacyNoVersion := "~V"
legacyNoKind := "~K"
legacyFieldSeparator := "_"
g := x.Group
if g == "" {
g = legacyNoGroup
}
v := x.Version
if v == "" {
v = legacyNoVersion
}
k := x.Kind
if k == "" {
k = legacyNoKind
}
return strings.Join([]string{g, v, k}, legacyFieldSeparator)
}
// legacyResIDSortString returns a string representation of given ResID used for
// stable sorting.
func legacyResIDSortString(id resid.ResId) string {
legacyNoNamespace := "~X"
legacyNoName := "~N"
legacySeparator := "|"
ns := id.Namespace
if ns == "" {
ns = legacyNoNamespace
}
nm := id.Name
if nm == "" {
nm = legacyNoName
}
return strings.Join(
[]string{id.Gvk.String(), ns, nm}, legacySeparator)
}
// DO NOT CHANGE!
// Final legacy ordering provided as a default by kustomize.
// Originally an attempt to apply resources in the correct order, an effort
// which later proved impossible as not all types are known beforehand.
// See: https://github.com/kubernetes-sigs/kustomize/issues/3913
var defaultOrderFirst = []string{ //nolint:gochecknoglobals
"Namespace",
"ResourceQuota",
"StorageClass",
"CustomResourceDefinition",
"ServiceAccount",
"PodSecurityPolicy",
"Role",
"ClusterRole",
"RoleBinding",
"ClusterRoleBinding",
"ConfigMap",
"Secret",
"Endpoints",
"Service",
"LimitRange",
"PriorityClass",
"PersistentVolume",
"PersistentVolumeClaim",
"Deployment",
"StatefulSet",
"CronJob",
"PodDisruptionBudget",
}
var defaultOrderLast = []string{ //nolint:gochecknoglobals
"MutatingWebhookConfiguration",
"ValidatingWebhookConfiguration",
}
func NewSortOrderTransformerPlugin() resmap.TransformerPlugin {
return &SortOrderTransformerPlugin{}
}

View File

@@ -1,5 +1,5 @@
// Code generated by pluginator on SuffixTransformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
// pluginator {(devel) unknown }
package builtins

View File

@@ -1,5 +1,5 @@
// Code generated by pluginator on ValueAddTransformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
// pluginator {(devel) unknown }
package builtins

View File

@@ -5,6 +5,8 @@ package generators
import (
"fmt"
"path"
"strings"
"github.com/go-errors/errors"
"sigs.k8s.io/kustomize/api/ifc"
@@ -95,3 +97,28 @@ func setImmutable(
return nil
}
// ParseFileSource parses the source given.
//
// Acceptable formats include:
// 1. source-path: the basename will become the key name
// 2. source-name=source-path: the source-name will become the key name and
// source-path is the path to the key file.
//
// Key names cannot include '='.
func ParseFileSource(source string) (keyName, filePath string, err error) {
numSeparators := strings.Count(source, "=")
switch {
case numSeparators == 0:
return path.Base(source), source, nil
case numSeparators == 1 && strings.HasPrefix(source, "="):
return "", "", errors.Errorf("missing key name for file path %q in source %q", strings.TrimPrefix(source, "="), source)
case numSeparators == 1 && strings.HasSuffix(source, "="):
return "", "", errors.Errorf("missing file path for key name %q in source %q", strings.TrimSuffix(source, "="), source)
case numSeparators > 1:
return "", "", errors.Errorf("source %q key name or file path contains '='", source)
default:
components := strings.Split(source, "=")
return components[0], components[1], nil
}
}

View File

@@ -22,15 +22,11 @@ func ClonerUsingGitExec(repoSpec *RepoSpec) error {
if err = r.run("init"); err != nil {
return err
}
if err = r.run(
"remote", "add", "origin", repoSpec.CloneSpec()); err != nil {
return err
}
ref := "HEAD"
if repoSpec.Ref != "" {
ref = repoSpec.Ref
}
if err = r.run("fetch", "--depth=1", "origin", ref); err != nil {
if err = r.run("fetch", "--depth=1", repoSpec.CloneSpec(), ref); err != nil {
return err
}
if err = r.run("checkout", "FETCH_HEAD"); err != nil {

View File

@@ -7,8 +7,8 @@ import (
"os/exec"
"time"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/internal/utils"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/filesys"
)
@@ -24,7 +24,7 @@ type gitRunner struct {
func newCmdRunner(timeout time.Duration) (*gitRunner, error) {
gitProgram, err := exec.LookPath("git")
if err != nil {
return nil, errors.Wrap(err, "no 'git' program on path")
return nil, errors.WrapPrefixf(err, "no 'git' program on path")
}
dir, err := filesys.NewTmpConfirmedDir()
if err != nil {
@@ -46,9 +46,9 @@ func (r gitRunner) run(args ...string) error {
cmd.String(),
r.duration,
func() error {
_, err := cmd.CombinedOutput()
out, err := cmd.CombinedOutput()
if err != nil {
return errors.Wrapf(err, "git cmd = '%s'", cmd.String())
return errors.WrapPrefixf(err, "failed to run '%s': %s", cmd.String(), string(out))
}
return err
})

View File

@@ -5,12 +5,15 @@ package git
import (
"fmt"
"log"
"net/url"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/filesys"
)
@@ -27,26 +30,23 @@ type RepoSpec struct {
// TODO(monopole): Drop raw, use processed fields instead.
raw string
// Host, e.g. github.com
// Host, e.g. https://github.com/
Host string
// orgRepo name (organization/repoName),
// RepoPath name (Path to repository),
// e.g. kubernetes-sigs/kustomize
OrgRepo string
RepoPath string
// Dir where the orgRepo is cloned to.
// Dir is where the repository is cloned to.
Dir filesys.ConfirmedDir
// Relative path in the repository, and in the cloneDir,
// to a Kustomization.
Path string
KustRootPath string
// Branch or tag reference.
Ref string
// e.g. .git or empty in case of _git is present
GitSuffix string
// Submodules indicates whether or not to clone git submodules.
Submodules bool
@@ -56,10 +56,7 @@ type RepoSpec struct {
// CloneSpec returns a string suitable for "git clone {spec}".
func (x *RepoSpec) CloneSpec() string {
if isAzureHost(x.Host) || isAWSHost(x.Host) {
return x.Host + x.OrgRepo
}
return x.Host + x.OrgRepo + x.GitSuffix
return x.Host + x.RepoPath
}
func (x *RepoSpec) CloneDir() filesys.ConfirmedDir {
@@ -71,81 +68,140 @@ func (x *RepoSpec) Raw() string {
}
func (x *RepoSpec) AbsPath() string {
return x.Dir.Join(x.Path)
return x.Dir.Join(x.KustRootPath)
}
func (x *RepoSpec) Cleaner(fSys filesys.FileSystem) func() error {
return func() error { return fSys.RemoveAll(x.Dir.String()) }
}
const (
refQuery = "?ref="
gitSuffix = ".git"
gitRootDelimiter = "_git/"
pathSeparator = "/" // do not use filepath.Separator, as this is a URL
)
// NewRepoSpecFromURL parses git-like urls.
// From strings like git@github.com:someOrg/someRepo.git or
// https://github.com/someOrg/someRepo?ref=someHash, extract
// the parts.
// the different parts of URL, set into a RepoSpec object and return RepoSpec object.
// It MUST return an error if the input is not a git-like URL, as this is used by some code paths
// to distinguish between local and remote paths.
//
// In particular, NewRepoSpecFromURL separates the URL used to clone the repo from the
// elements Kustomize uses for other purposes (e.g. query params that turn into args, and
// the path to the kustomization root within the repo).
func NewRepoSpecFromURL(n string) (*RepoSpec, error) {
repoSpec := &RepoSpec{raw: n, Dir: notCloned, Timeout: defaultTimeout, Submodules: defaultSubmodules}
if filepath.IsAbs(n) {
return nil, fmt.Errorf("uri looks like abs path: %s", n)
}
host, orgRepo, path, gitRef, gitSubmodules, suffix, gitTimeout := parseGitURL(n)
if orgRepo == "" {
return nil, fmt.Errorf("url lacks orgRepo: %s", n)
// Parse the query first. This is safe because according to rfc3986 "?" is only allowed in the
// query and is not recognized %-encoded.
// Note that parseQuery returns default values for empty parameters.
n, query, _ := strings.Cut(n, "?")
repoSpec.Ref, repoSpec.Timeout, repoSpec.Submodules = parseQuery(query)
var err error
// Parse the host (e.g. scheme, username, domain) segment.
repoSpec.Host, n, err = extractHost(n)
if err != nil {
return nil, err
}
if host == "" {
return nil, fmt.Errorf("url lacks host: %s", n)
// In some cases, we're given a path to a git repo + a path to the kustomization root within
// that repo. We need to split them so that we can ultimately give the repo only to the cloner.
repoSpec.RepoPath, repoSpec.KustRootPath, err = parsePathParts(n, defaultRepoPathLength(repoSpec.Host))
if err != nil {
return nil, err
}
return &RepoSpec{
raw: n, Host: host, OrgRepo: orgRepo,
Dir: notCloned, Path: path, Ref: gitRef, GitSuffix: suffix,
Submodules: gitSubmodules, Timeout: gitTimeout}, nil
return repoSpec, nil
}
const (
refQuery = "?ref="
gitSuffix = ".git"
gitDelimiter = "_git/"
)
const allSegments = -999999
const orgRepoSegments = 2
// From strings like git@github.com:someOrg/someRepo.git or
// https://github.com/someOrg/someRepo?ref=someHash, extract
// the parts.
func parseGitURL(n string) (
host string, orgRepo string, path string, gitRef string, gitSubmodules bool, gitSuff string, gitTimeout time.Duration) {
if strings.Contains(n, gitDelimiter) {
index := strings.Index(n, gitDelimiter)
// Adding _git/ to host
host = normalizeGitHostSpec(n[:index+len(gitDelimiter)])
orgRepo = strings.Split(strings.Split(n[index+len(gitDelimiter):], "/")[0], "?")[0]
path, gitRef, gitTimeout, gitSubmodules = peelQuery(n[index+len(gitDelimiter)+len(orgRepo):])
return
func defaultRepoPathLength(host string) int {
if strings.HasPrefix(host, fileScheme) {
return allSegments
}
host, n = parseHostSpec(n)
gitSuff = gitSuffix
if strings.Contains(n, gitSuffix) {
index := strings.Index(n, gitSuffix)
orgRepo = n[0:index]
n = n[index+len(gitSuffix):]
if len(n) > 0 && n[0] == '/' {
n = n[1:]
}
path, gitRef, gitTimeout, gitSubmodules = peelQuery(n)
return
return orgRepoSegments
}
// parsePathParts splits the repo path that will ultimately be passed to git to clone the
// repo from the kustomization root path, which Kustomize will execute the build in after the repo
// is cloned.
//
// We first try to do this based on explicit markers in the URL (e.g. _git, .git or //).
// If none are present, we try to apply a historical default repo path length that is derived from
// Github URLs. If there aren't enough segments, we have historically considered the URL invalid.
func parsePathParts(n string, defaultSegmentLength int) (string, string, error) {
repoPath, kustRootPath, success := tryExplicitMarkerSplit(n)
if !success {
repoPath, kustRootPath, success = tryDefaultLengthSplit(n, defaultSegmentLength)
}
i := strings.Index(n, "/")
if i < 1 {
path, gitRef, gitTimeout, gitSubmodules = peelQuery(n)
return
// Validate the result
if !success || len(repoPath) == 0 {
return "", "", fmt.Errorf("failed to parse repo path segment")
}
j := strings.Index(n[i+1:], "/")
if j >= 0 {
j += i + 1
orgRepo = n[:j]
path, gitRef, gitTimeout, gitSubmodules = peelQuery(n[j+1:])
return
if kustRootPathExitsRepo(kustRootPath) {
return "", "", fmt.Errorf("url path exits repo: %s", n)
}
path = ""
orgRepo, gitRef, gitTimeout, gitSubmodules = peelQuery(n)
return host, orgRepo, path, gitRef, gitSubmodules, gitSuff, gitTimeout
return repoPath, strings.TrimPrefix(kustRootPath, pathSeparator), nil
}
func tryExplicitMarkerSplit(n string) (string, string, bool) {
// Look for the _git delimiter, which by convention is expected to be ONE directory above the repo root.
// If found, split on the NEXT path element, which is the repo root.
// Example: https://username@dev.azure.com/org/project/_git/repo/path/to/kustomization/root
if gitRootIdx := strings.Index(n, gitRootDelimiter); gitRootIdx >= 0 {
gitRootPath := n[:gitRootIdx+len(gitRootDelimiter)]
subpathSegments := strings.Split(n[gitRootIdx+len(gitRootDelimiter):], pathSeparator)
return gitRootPath + subpathSegments[0], strings.Join(subpathSegments[1:], pathSeparator), true
// Look for a double-slash in the path, which if present separates the repo root from the kust path.
// It is a convention, not a real path element, so do not preserve it in the returned value.
// Example: https://github.com/org/repo//path/to/kustomozation/root
} else if repoRootIdx := strings.Index(n, "//"); repoRootIdx >= 0 {
return n[:repoRootIdx], n[repoRootIdx+2:], true
// Look for .git in the path, which if present is part of the directory name of the git repo.
// This means we want to grab everything up to and including that suffix
// Example: https://github.com/org/repo.git/path/to/kustomozation/root
} else if gitSuffixIdx := strings.Index(n, gitSuffix); gitSuffixIdx >= 0 {
upToGitSuffix := n[:gitSuffixIdx+len(gitSuffix)]
afterGitSuffix := n[gitSuffixIdx+len(gitSuffix):]
return upToGitSuffix, afterGitSuffix, true
}
return "", "", false
}
func tryDefaultLengthSplit(n string, defaultSegmentLength int) (string, string, bool) {
// If the default is to take all segments, do so.
if defaultSegmentLength == allSegments {
return n, "", true
// If the default is N segments, make sure we have at least that many and take them if so.
// If we have less than N, we have historically considered the URL invalid.
} else if segments := strings.Split(n, pathSeparator); len(segments) >= defaultSegmentLength {
firstNSegments := strings.Join(segments[:defaultSegmentLength], pathSeparator)
rest := strings.Join(segments[defaultSegmentLength:], pathSeparator)
return firstNSegments, rest, true
}
return "", "", false
}
func kustRootPathExitsRepo(kustRootPath string) bool {
cleanedPath := filepath.Clean(strings.TrimPrefix(kustRootPath, string(filepath.Separator)))
pathElements := strings.Split(cleanedPath, string(filepath.Separator))
return len(pathElements) > 0 &&
pathElements[0] == filesys.ParentDir
}
// Clone git submodules by default.
@@ -154,14 +210,12 @@ const defaultSubmodules = true
// Arbitrary, but non-infinite, timeout for running commands.
const defaultTimeout = 27 * time.Second
func peelQuery(arg string) (string, string, time.Duration, bool) {
// Parse the given arg into a URL. In the event of a parse failure, return
// our defaults.
parsed, err := url.Parse(arg)
func parseQuery(query string) (string, time.Duration, bool) {
values, err := url.ParseQuery(query)
// in event of parse failure, return defaults
if err != nil {
return arg, "", defaultTimeout, defaultSubmodules
return "", defaultTimeout, defaultSubmodules
}
values := parsed.Query()
// ref is the desired git ref to target. Can be specified by in a git URL
// with ?ref=<string> or ?version=<string>, although ref takes precedence.
@@ -192,76 +246,142 @@ func peelQuery(arg string) (string, string, time.Duration, bool) {
}
}
return parsed.Path, ref, duration, submodules
return ref, duration, submodules
}
func parseHostSpec(n string) (string, string) {
var host string
// Start accumulating the host part.
for _, p := range []string{
// Order matters here.
"git::", "gh:", "ssh://", "https://", "http://",
"git@", "github.com:", "github.com/"} {
if len(p) < len(n) && strings.ToLower(n[:len(p)]) == p {
n = n[len(p):]
host += p
func extractHost(n string) (string, string, error) {
n = ignoreForcedGitProtocol(n)
scheme, n := extractScheme(n)
username, n := extractUsername(n)
stdGithub := isStandardGithubHost(n)
acceptSCP := acceptSCPStyle(scheme, username, stdGithub)
// Validate the username and scheme before attempting host/path parsing, because if the parsing
// so far has not succeeded, we will not be able to extract the host and path correctly.
if err := validateScheme(scheme, acceptSCP); err != nil {
return "", "", err
}
// Now that we have extracted a valid scheme+username, we can parse host itself.
// The file protocol specifies an absolute path to a local git repo.
// Everything after the scheme (including any 'username' we found) is actually part of that path.
if scheme == fileScheme {
return scheme, username + n, nil
}
var host, rest = n, ""
if sepIndex := findPathSeparator(n, acceptSCP); sepIndex >= 0 {
host, rest = n[:sepIndex+1], n[sepIndex+1:]
}
// Github URLs are strictly normalized in a way that may discard scheme and username components.
if stdGithub {
scheme, username, host = normalizeGithubHostParts(scheme, username)
}
// Host is required, so do not concat the scheme and username if we didn't find one.
if host == "" {
return "", "", errors.Errorf("failed to parse host segment")
}
return scheme + username + host, rest, nil
}
// ignoreForcedGitProtocol strips the "git::" prefix from URLs.
// We used to use go-getter to handle our urls: https://github.com/hashicorp/go-getter.
// The git:: prefix signaled go-getter to use the git protocol to fetch the url's contents.
// We silently strip this prefix to allow these go-getter-style urls to continue to work,
// although the git protocol (which is insecure and unsupported on many platforms, including Github)
// will not actually be used as intended.
func ignoreForcedGitProtocol(n string) string {
n, found := trimPrefixIgnoreCase(n, "git::")
if found {
log.Println("Warning: Forcing the git protocol using the 'git::' URL prefix is not supported. " +
"Kustomize currently strips this invalid prefix, but will stop doing so in a future release. " +
"Please remove the 'git::' prefix from your configuration.")
}
return n
}
// acceptSCPStyle returns true if the scheme and username indicate potential use of an SCP-style URL.
// With this style, the scheme is not explicit and the path is delimited by a colon.
// Strictly speaking the username is optional in SCP-like syntax, but Kustomize has always
// required it for non-Github URLs.
// Example: user@host.xz:path/to/repo.git/
func acceptSCPStyle(scheme, username string, isGithubURL bool) bool {
return scheme == "" && (username != "" || isGithubURL)
}
func validateScheme(scheme string, acceptSCPStyle bool) error {
// see https://git-scm.com/docs/git-fetch#_git_urls for info relevant to these validations
switch scheme {
case "":
// Empty scheme is only ok if it's a Github URL or if it looks like SCP-style syntax
if !acceptSCPStyle {
return fmt.Errorf("failed to parse scheme")
}
case sshScheme, fileScheme, httpsScheme, httpScheme:
// These are all supported schemes
default:
// At time of writing, we should never end up here because we do not parse out
// unsupported schemes to begin with.
return fmt.Errorf("unsupported scheme %q", scheme)
}
return nil
}
const fileScheme = "file://"
const httpScheme = "http://"
const httpsScheme = "https://"
const sshScheme = "ssh://"
func extractScheme(s string) (string, string) {
for _, prefix := range []string{sshScheme, httpsScheme, httpScheme, fileScheme} {
if rest, found := trimPrefixIgnoreCase(s, prefix); found {
return prefix, rest
}
}
if host == "git@" {
i := strings.Index(n, "/")
if i > -1 {
host += n[:i+1]
n = n[i+1:]
} else {
i = strings.Index(n, ":")
if i > -1 {
host += n[:i+1]
n = n[i+1:]
}
}
return host, n
}
return "", s
}
// If host is a http(s) or ssh URL, grab the domain part.
for _, p := range []string{
"ssh://", "https://", "http://"} {
if strings.HasSuffix(host, p) {
i := strings.Index(n, "/")
if i > -1 {
host += n[0 : i+1]
n = n[i+1:]
}
break
func extractUsername(s string) (string, string) {
var userRegexp = regexp.MustCompile(`^([a-zA-Z][a-zA-Z0-9-]*)@`)
if m := userRegexp.FindStringSubmatch(s); m != nil {
username := m[1] + "@"
return username, s[len(username):]
}
return "", s
}
func isStandardGithubHost(s string) bool {
lowerCased := strings.ToLower(s)
return strings.HasPrefix(lowerCased, "github.com/") ||
strings.HasPrefix(lowerCased, "github.com:")
}
// trimPrefixIgnoreCase returns the rest of s and true if prefix, ignoring case, prefixes s.
// Otherwise, trimPrefixIgnoreCase returns s and false.
func trimPrefixIgnoreCase(s, prefix string) (string, bool) {
if len(prefix) <= len(s) && strings.ToLower(s[:len(prefix)]) == prefix {
return s[len(prefix):], true
}
return s, false
}
func findPathSeparator(hostPath string, acceptSCP bool) int {
sepIndex := strings.Index(hostPath, pathSeparator)
if acceptSCP {
colonIndex := strings.Index(hostPath, ":")
// The colon acts as a delimiter in scp-style ssh URLs only if not prefixed by '/'.
if sepIndex == -1 || (colonIndex > 0 && colonIndex < sepIndex) {
sepIndex = colonIndex
}
}
return normalizeGitHostSpec(host), n
return sepIndex
}
func normalizeGitHostSpec(host string) string {
s := strings.ToLower(host)
if strings.Contains(s, "github.com") {
if strings.Contains(s, "git@") || strings.Contains(s, "ssh:") {
host = "git@github.com:"
} else {
host = "https://github.com/"
}
func normalizeGithubHostParts(scheme, username string) (string, string, string) {
if strings.HasPrefix(scheme, sshScheme) || username != "" {
return "", username, "github.com:"
}
if strings.HasPrefix(s, "git::") {
host = strings.TrimPrefix(s, "git::")
}
return host
}
// The format of Azure repo URL is documented
// https://docs.microsoft.com/en-us/azure/devops/repos/git/clone?view=vsts&tabs=visual-studio#clone_url
func isAzureHost(host string) bool {
return strings.Contains(host, "dev.azure.com") ||
strings.Contains(host, "visualstudio.com")
}
// The format of AWS repo URL is documented
// https://docs.aws.amazon.com/codecommit/latest/userguide/regions.html
func isAWSHost(host string) bool {
return strings.Contains(host, "amazonaws.com")
return httpsScheme, "", "github.com/"
}

View File

@@ -22,7 +22,7 @@ import (
// contains a Pod; Deployment, Job, StatefulSet, etc.
// The ConfigMap is the ReferralTarget, the others are Referrers.
//
// If the the name of a ConfigMap instance changed from 'alice' to 'bob',
// If the name of a ConfigMap instance changed from 'alice' to 'bob',
// one must
// - visit all objects that could refer to the ConfigMap (the Referrers)
// - see if they mention 'alice',

View File

@@ -10,6 +10,7 @@ import (
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/konfig/builtinpluginconsts"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/errors"
)
// TransformerConfig holds the data needed to perform transformations.
@@ -18,6 +19,7 @@ type TransformerConfig struct {
NameSuffix types.FsSlice `json:"nameSuffix,omitempty" yaml:"nameSuffix,omitempty"`
NameSpace types.FsSlice `json:"namespace,omitempty" yaml:"namespace,omitempty"`
CommonLabels types.FsSlice `json:"commonLabels,omitempty" yaml:"commonLabels,omitempty"`
TemplateLabels types.FsSlice `json:"templateLabels,omitempty" yaml:"templateLabels,omitempty"`
CommonAnnotations types.FsSlice `json:"commonAnnotations,omitempty" yaml:"commonAnnotations,omitempty"`
NameReference nbrSlice `json:"nameReference,omitempty" yaml:"nameReference,omitempty"`
VarReference types.FsSlice `json:"varReference,omitempty" yaml:"varReference,omitempty"`
@@ -58,8 +60,10 @@ func MakeTransformerConfig(
// sortFields provides determinism in logging, tests, etc.
func (t *TransformerConfig) sortFields() {
sort.Sort(t.NamePrefix)
sort.Sort(t.NameSuffix)
sort.Sort(t.NameSpace)
sort.Sort(t.CommonLabels)
sort.Sort(t.TemplateLabels)
sort.Sort(t.CommonAnnotations)
sort.Sort(t.NameReference)
sort.Sort(t.VarReference)
@@ -108,40 +112,44 @@ func (t *TransformerConfig) Merge(input *TransformerConfig) (
merged = &TransformerConfig{}
merged.NamePrefix, err = t.NamePrefix.MergeAll(input.NamePrefix)
if err != nil {
return nil, err
return nil, errors.WrapPrefixf(err, "failed to merge NamePrefix fieldSpec")
}
merged.NameSuffix, err = t.NameSuffix.MergeAll(input.NameSuffix)
if err != nil {
return nil, err
return nil, errors.WrapPrefixf(err, "failed to merge NameSuffix fieldSpec")
}
merged.NameSpace, err = t.NameSpace.MergeAll(input.NameSpace)
if err != nil {
return nil, err
return nil, errors.WrapPrefixf(err, "failed to merge NameSpace fieldSpec")
}
merged.CommonAnnotations, err = t.CommonAnnotations.MergeAll(
input.CommonAnnotations)
if err != nil {
return nil, err
return nil, errors.WrapPrefixf(err, "failed to merge CommonAnnotations fieldSpec")
}
merged.CommonLabels, err = t.CommonLabels.MergeAll(input.CommonLabels)
if err != nil {
return nil, err
return nil, errors.WrapPrefixf(err, "failed to merge CommonLabels fieldSpec")
}
merged.TemplateLabels, err = t.TemplateLabels.MergeAll(input.TemplateLabels)
if err != nil {
return nil, errors.WrapPrefixf(err, "failed to merge TemplateLabels fieldSpec")
}
merged.VarReference, err = t.VarReference.MergeAll(input.VarReference)
if err != nil {
return nil, err
return nil, errors.WrapPrefixf(err, "failed to merge VarReference fieldSpec")
}
merged.NameReference, err = t.NameReference.mergeAll(input.NameReference)
if err != nil {
return nil, err
return nil, errors.WrapPrefixf(err, "failed to merge NameReference fieldSpec")
}
merged.Images, err = t.Images.MergeAll(input.Images)
if err != nil {
return nil, err
return nil, errors.WrapPrefixf(err, "failed to merge Images fieldSpec")
}
merged.Replicas, err = t.Replicas.MergeAll(input.Replicas)
if err != nil {
return nil, err
return nil, errors.WrapPrefixf(err, "failed to merge Replicas fieldSpec")
}
merged.sortFields()
return merged, nil

View File

@@ -15,24 +15,23 @@ func _() {
_ = x[HashTransformer-4]
_ = x[ImageTagTransformer-5]
_ = x[LabelTransformer-6]
_ = x[LegacyOrderTransformer-7]
_ = x[NamespaceTransformer-8]
_ = x[PatchJson6902Transformer-9]
_ = x[PatchStrategicMergeTransformer-10]
_ = x[PatchTransformer-11]
_ = x[PrefixSuffixTransformer-12]
_ = x[PrefixTransformer-13]
_ = x[SuffixTransformer-14]
_ = x[ReplicaCountTransformer-15]
_ = x[SecretGenerator-16]
_ = x[ValueAddTransformer-17]
_ = x[HelmChartInflationGenerator-18]
_ = x[ReplacementTransformer-19]
_ = x[NamespaceTransformer-7]
_ = x[PatchJson6902Transformer-8]
_ = x[PatchStrategicMergeTransformer-9]
_ = x[PatchTransformer-10]
_ = x[PrefixSuffixTransformer-11]
_ = x[PrefixTransformer-12]
_ = x[SuffixTransformer-13]
_ = x[ReplicaCountTransformer-14]
_ = x[SecretGenerator-15]
_ = x[ValueAddTransformer-16]
_ = x[HelmChartInflationGenerator-17]
_ = x[ReplacementTransformer-18]
}
const _BuiltinPluginType_name = "UnknownAnnotationsTransformerConfigMapGeneratorIAMPolicyGeneratorHashTransformerImageTagTransformerLabelTransformerLegacyOrderTransformerNamespaceTransformerPatchJson6902TransformerPatchStrategicMergeTransformerPatchTransformerPrefixSuffixTransformerPrefixTransformerSuffixTransformerReplicaCountTransformerSecretGeneratorValueAddTransformerHelmChartInflationGeneratorReplacementTransformer"
const _BuiltinPluginType_name = "UnknownAnnotationsTransformerConfigMapGeneratorIAMPolicyGeneratorHashTransformerImageTagTransformerLabelTransformerNamespaceTransformerPatchJson6902TransformerPatchStrategicMergeTransformerPatchTransformerPrefixSuffixTransformerPrefixTransformerSuffixTransformerReplicaCountTransformerSecretGeneratorValueAddTransformerHelmChartInflationGeneratorReplacementTransformer"
var _BuiltinPluginType_index = [...]uint16{0, 7, 29, 47, 65, 80, 99, 115, 137, 157, 181, 211, 227, 250, 267, 284, 307, 322, 341, 368, 390}
var _BuiltinPluginType_index = [...]uint16{0, 7, 29, 47, 65, 80, 99, 115, 135, 159, 189, 205, 228, 245, 262, 285, 300, 319, 346, 368}
func (i BuiltinPluginType) String() string {
if i < 0 || i >= BuiltinPluginType(len(_BuiltinPluginType_index)-1) {

View File

@@ -19,7 +19,6 @@ const (
HashTransformer
ImageTagTransformer
LabelTransformer
LegacyOrderTransformer
NamespaceTransformer
PatchJson6902Transformer
PatchStrategicMergeTransformer
@@ -100,7 +99,6 @@ var TransformerFactories = map[BuiltinPluginType]func() resmap.TransformerPlugin
HashTransformer: builtins.NewHashTransformerPlugin,
ImageTagTransformer: builtins.NewImageTagTransformerPlugin,
LabelTransformer: builtins.NewLabelTransformerPlugin,
LegacyOrderTransformer: builtins.NewLegacyOrderTransformerPlugin,
NamespaceTransformer: builtins.NewNamespaceTransformerPlugin,
PatchJson6902Transformer: builtins.NewPatchJson6902TransformerPlugin,
PatchStrategicMergeTransformer: builtins.NewPatchStrategicMergeTransformerPlugin,
@@ -111,4 +109,7 @@ var TransformerFactories = map[BuiltinPluginType]func() resmap.TransformerPlugin
ReplacementTransformer: builtins.NewReplacementTransformerPlugin,
ReplicaCountTransformer: builtins.NewReplicaCountTransformerPlugin,
ValueAddTransformer: builtins.NewValueAddTransformerPlugin,
// Do not wired SortOrderTransformer as a builtin plugin.
// We only want it to be available in the top-level kustomization.
// See: https://github.com/kubernetes-sigs/kustomize/issues/3913
}

View File

@@ -6,7 +6,6 @@ package execplugin
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"os/exec"
"runtime"
@@ -14,9 +13,9 @@ import (
"github.com/google/shlex"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/internal/plugins/utils"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/yaml"
)
@@ -150,19 +149,19 @@ func (p *ExecPlugin) Transform(rm resmap.ResMap) error {
// passes the full temp file path as the first arg to a process
// running the plugin binary. Process output is returned.
func (p *ExecPlugin) invokePlugin(input []byte) ([]byte, error) {
f, err := ioutil.TempFile("", tmpConfigFilePrefix)
f, err := os.CreateTemp("", tmpConfigFilePrefix)
if err != nil {
return nil, errors.Wrap(
return nil, errors.WrapPrefixf(
err, "creating tmp plugin config file")
}
_, err = f.Write(p.cfg)
if err != nil {
return nil, errors.Wrap(
return nil, errors.WrapPrefixf(
err, "writing plugin config to "+f.Name())
}
err = f.Close()
if err != nil {
return nil, errors.Wrap(
return nil, errors.WrapPrefixf(
err, "closing plugin config file "+f.Name())
}
//nolint:gosec
@@ -176,7 +175,7 @@ func (p *ExecPlugin) invokePlugin(input []byte) ([]byte, error) {
}
result, err := cmd.Output()
if err != nil {
return nil, errors.Wrapf(
return nil, errors.WrapPrefixf(
err, "failure in plugin configured via %s; %v",
f.Name(), err.Error())
}

View File

@@ -7,7 +7,7 @@ import (
"bytes"
"fmt"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/api/internal/plugins/utils"
"sigs.k8s.io/kustomize/api/resmap"
@@ -51,13 +51,16 @@ func resourceToRNode(res *resource.Resource) (*yaml.RNode, error) {
}
// GetFunctionSpec return function spec is there is. Otherwise return nil
func GetFunctionSpec(res *resource.Resource) *runtimeutil.FunctionSpec {
func GetFunctionSpec(res *resource.Resource) (*runtimeutil.FunctionSpec, error) {
rnode, err := resourceToRNode(res)
if err != nil {
return nil
return nil, fmt.Errorf("could not convert resource to RNode: %w", err)
}
return runtimeutil.GetFunctionSpec(rnode)
functionSpec, err := runtimeutil.GetFunctionSpec(rnode)
if err != nil {
return nil, fmt.Errorf("failed to get FunctionSpec: %w", err)
}
return functionSpec, nil
}
func toStorageMounts(mounts []string) []runtimeutil.StorageMount {
@@ -191,7 +194,7 @@ func (p *FnPlugin) invokePlugin(input []byte) ([]byte, error) {
err = p.runFns.Execute()
if err != nil {
return nil, errors.Wrap(
return nil, errors.WrapPrefixf(
err, "couldn't execute function")
}

View File

@@ -12,7 +12,6 @@ import (
"reflect"
"strings"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers"
"sigs.k8s.io/kustomize/api/internal/plugins/execplugin"
@@ -22,6 +21,7 @@ import (
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/filesys"
"sigs.k8s.io/kustomize/kyaml/resid"
)
@@ -42,27 +42,35 @@ func NewLoader(
return &Loader{pc: pc, rf: rf, fs: fs}
}
// LoaderWithWorkingDir returns loader after setting its working directory.
// NOTE: This is not really a new loader since some of the Loader struct fields are pointers.
func (l *Loader) LoaderWithWorkingDir(wd string) *Loader {
lpc := &types.PluginConfig{
PluginRestrictions: l.pc.PluginRestrictions,
BpLoadingOptions: l.pc.BpLoadingOptions,
FnpLoadingOptions: l.pc.FnpLoadingOptions,
HelmConfig: l.pc.HelmConfig,
}
lpc.FnpLoadingOptions.WorkingDir = wd
return &Loader{pc: lpc, rf: l.rf, fs: l.fs}
}
// Config provides the global (not plugin specific) PluginConfig data.
func (l *Loader) Config() *types.PluginConfig {
return l.pc
}
// SetWorkDir sets the working directory for this loader's plugins
func (l *Loader) SetWorkDir(wd string) {
l.pc.FnpLoadingOptions.WorkingDir = wd
}
func (l *Loader) LoadGenerators(
ldr ifc.Loader, v ifc.Validator, rm resmap.ResMap) (
result []*resmap.GeneratorWithProperties, err error) {
for _, res := range rm.Resources() {
g, err := l.LoadGenerator(ldr, v, res)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to load generator: %w", err)
}
generatorOrigin, err := resource.OriginFromCustomPlugin(res)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to get origin from CustomPlugin: %w", err)
}
result = append(result, &resmap.GeneratorWithProperties{Generator: g, Origin: generatorOrigin})
}
@@ -130,15 +138,19 @@ func (l *Loader) AbsolutePluginPath(id resid.ResId) (string, error) {
// absPluginHome is the home of kustomize Exec and Go plugins.
// Kustomize plugin configuration files are k8s-style objects
// containing the fields 'apiVersion' and 'kind', e.g.
// apiVersion: apps/v1
// kind: Deployment
//
// apiVersion: apps/v1
// kind: Deployment
//
// kustomize reads plugin configuration data from a file path
// specified in the 'generators:' or 'transformers:' field of a
// kustomization file. For Exec and Go plugins, kustomize
// uses this data to both locate the plugin and configure it.
// Each Exec or Go plugin (its code, its tests, its supporting data
// files, etc.) must be housed in its own directory at
// ${absPluginHome}/${pluginApiVersion}/LOWERCASE(${pluginKind})
//
// ${absPluginHome}/${pluginApiVersion}/LOWERCASE(${pluginKind})
//
// where
// - ${absPluginHome} is an absolute path, defined below.
// - ${pluginApiVersion} is taken from the plugin config file.
@@ -204,11 +216,11 @@ func (l *Loader) loadAndConfigurePlugin(
}
yaml, err := res.AsYAML()
if err != nil {
return nil, errors.Wrapf(err, "marshalling yaml from res %s", res.OrgId())
return nil, errors.WrapPrefixf(err, "marshalling yaml from res %s", res.OrgId())
}
err = c.Config(resmap.NewPluginHelpers(ldr, v, l.rf, l.pc), yaml)
if err != nil {
return nil, errors.Wrapf(
return nil, errors.WrapPrefixf(
err, "plugin %s fails configuration", res.OrgId())
}
return c, nil
@@ -226,17 +238,20 @@ func (l *Loader) makeBuiltinPlugin(r resid.Gvk) (resmap.Configurable, error) {
}
func (l *Loader) loadPlugin(res *resource.Resource) (resmap.Configurable, error) {
spec := fnplugin.GetFunctionSpec(res)
spec, err := fnplugin.GetFunctionSpec(res)
if err != nil {
return nil, fmt.Errorf("loader: %w", err)
}
if spec != nil {
// validation check that function mounts are under the current kustomization directory
for _, mount := range spec.Container.StorageMounts {
if filepath.IsAbs(mount.Src) {
return nil, errors.New(fmt.Sprintf("plugin %s with mount path '%s' is not permitted; "+
"mount paths must be relative to the current kustomization directory", res.OrgId(), mount.Src))
return nil, errors.Errorf("plugin %s with mount path '%s' is not permitted; "+
"mount paths must be relative to the current kustomization directory", res.OrgId(), mount.Src)
}
if strings.HasPrefix(filepath.Clean(mount.Src), "../") {
return nil, errors.New(fmt.Sprintf("plugin %s with mount path '%s' is not permitted; "+
"mount paths must be under the current kustomization directory", res.OrgId(), mount.Src))
return nil, errors.Errorf("plugin %s with mount path '%s' is not permitted; "+
"mount paths must be under the current kustomization directory", res.OrgId(), mount.Src)
}
}
return fnplugin.NewFnPlugin(&l.pc.FnpLoadingOptions), nil
@@ -292,11 +307,11 @@ func (l *Loader) loadGoPlugin(id resid.ResId, absPath string) (resmap.Configurab
log.Printf("Attempting plugin load from '%s'", absPath)
p, err := plugin.Open(absPath)
if err != nil {
return nil, errors.Wrapf(err, "plugin %s fails to load", absPath)
return nil, errors.WrapPrefixf(err, "plugin %s fails to load", absPath)
}
symbol, err := p.Lookup(konfig.PluginSymbol)
if err != nil {
return nil, errors.Wrapf(
return nil, errors.WrapPrefixf(
err, "plugin %s doesn't have symbol %s",
regId, konfig.PluginSymbol)
}

View File

@@ -7,8 +7,8 @@ import (
"fmt"
"strings"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/kyaml/errors"
)
type errMissingKustomization struct {
@@ -23,12 +23,8 @@ func (e *errMissingKustomization) Error() string {
}
func IsMissingKustomizationFileError(err error) bool {
_, ok := err.(*errMissingKustomization)
if ok {
return true
}
_, ok = errors.Cause(err).(*errMissingKustomization)
return ok
e := &errMissingKustomization{}
return errors.As(err, &e)
}
func NewErrMissingKustomization(p string) *errMissingKustomization {

View File

@@ -6,10 +6,9 @@ package target
import (
"encoding/json"
"fmt"
"os"
"strings"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/internal/accumulator"
"sigs.k8s.io/kustomize/api/internal/builtins"
@@ -23,6 +22,7 @@ import (
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/yaml"
)
@@ -44,32 +44,40 @@ func NewKustTarget(
validator ifc.Validator,
rFactory *resmap.Factory,
pLdr *loader.Loader) *KustTarget {
pLdrCopy := *pLdr
pLdrCopy.SetWorkDir(ldr.Root())
return &KustTarget{
ldr: ldr,
validator: validator,
rFactory: rFactory,
pLdr: &pLdrCopy,
pLdr: pLdr.LoaderWithWorkingDir(ldr.Root()),
}
}
// Load attempts to load the target's kustomization file.
func (kt *KustTarget) Load() error {
content, kustFileName, err := loadKustFile(kt.ldr)
if err != nil {
return err
}
content, err = types.FixKustomizationPreUnmarshalling(content)
content, kustFileName, err := LoadKustFile(kt.ldr)
if err != nil {
return err
}
var k types.Kustomization
err = k.Unmarshal(content)
if err != nil {
if err := k.Unmarshal(content); err != nil {
return err
}
k.FixKustomizationPostUnmarshalling()
// show warning message when using deprecated fields.
if warningMessages := k.CheckDeprecatedFields(); warningMessages != nil {
for _, msg := range *warningMessages {
fmt.Fprintf(os.Stderr, "%v\n", msg)
}
}
k.FixKustomization()
// check that Kustomization is empty
if err := k.CheckEmpty(); err != nil {
return err
}
errs := k.EnforceFields()
if len(errs) > 0 {
return fmt.Errorf(
@@ -89,7 +97,7 @@ func (kt *KustTarget) Kustomization() types.Kustomization {
return result
}
func loadKustFile(ldr ifc.Loader) ([]byte, string, error) {
func LoadKustFile(ldr ifc.Loader) ([]byte, string, error) {
var content []byte
match := 0
var kustFileName string
@@ -150,6 +158,11 @@ func (kt *KustTarget) makeCustomizedResMap() (resmap.ResMap, error) {
return nil, err
}
err = kt.IgnoreLocal(ra)
if err != nil {
return nil, err
}
return ra.ResMap(), nil
}
@@ -187,11 +200,11 @@ func (kt *KustTarget) accumulateTarget(ra *accumulator.ResAccumulator) (
resRa *accumulator.ResAccumulator, err error) {
ra, err = kt.accumulateResources(ra, kt.kustomization.Resources)
if err != nil {
return nil, errors.Wrap(err, "accumulating resources")
return nil, errors.WrapPrefixf(err, "accumulating resources")
}
ra, err = kt.accumulateComponents(ra, kt.kustomization.Components)
if err != nil {
return nil, errors.Wrap(err, "accumulating components")
return nil, errors.WrapPrefixf(err, "accumulating components")
}
tConfig, err := builtinconfig.MakeTransformerConfig(
kt.ldr, kt.kustomization.Configurations)
@@ -200,17 +213,17 @@ func (kt *KustTarget) accumulateTarget(ra *accumulator.ResAccumulator) (
}
err = ra.MergeConfig(tConfig)
if err != nil {
return nil, errors.Wrapf(
return nil, errors.WrapPrefixf(
err, "merging config %v", tConfig)
}
crdTc, err := accumulator.LoadConfigFromCRDs(kt.ldr, kt.kustomization.Crds)
if err != nil {
return nil, errors.Wrapf(
return nil, errors.WrapPrefixf(
err, "loading CRDs %v", kt.kustomization.Crds)
}
err = ra.MergeConfig(crdTc)
if err != nil {
return nil, errors.Wrapf(
return nil, errors.WrapPrefixf(
err, "merging CRDs %v", crdTc)
}
err = kt.runGenerators(ra)
@@ -227,13 +240,9 @@ func (kt *KustTarget) accumulateTarget(ra *accumulator.ResAccumulator) (
}
err = ra.MergeVars(kt.kustomization.Vars)
if err != nil {
return nil, errors.Wrapf(
return nil, errors.WrapPrefixf(
err, "merging vars %v", kt.kustomization.Vars)
}
err = kt.IgnoreLocal(ra)
if err != nil {
return nil, err
}
return ra, nil
}
@@ -261,7 +270,7 @@ func (kt *KustTarget) runGenerators(
gs, err = kt.configureExternalGenerators()
if err != nil {
return errors.Wrap(err, "loading generator plugins")
return errors.WrapPrefixf(err, "loading generator plugins")
}
generators = append(generators, gs...)
for i, g := range generators {
@@ -272,12 +281,12 @@ func (kt *KustTarget) runGenerators(
if resMap != nil {
err = resMap.AddOriginAnnotation(generators[i].Origin)
if err != nil {
return errors.Wrapf(err, "adding origin annotations for generator %v", g)
return errors.WrapPrefixf(err, "adding origin annotations for generator %v", g)
}
}
err = ra.AbsorbAll(resMap)
if err != nil {
return errors.Wrapf(err, "merging from generator %v", g)
return errors.WrapPrefixf(err, "merging from generator %v", g)
}
}
return nil
@@ -304,7 +313,7 @@ func (kt *KustTarget) configureExternalGenerators() (
}
}
if err = ra.AppendAll(rm); err != nil {
return nil, errors.Wrapf(err, "configuring external generator")
return nil, errors.WrapPrefixf(err, "configuring external generator")
}
}
ra, err := kt.accumulateResources(ra, generatorPaths)
@@ -351,7 +360,7 @@ func (kt *KustTarget) configureExternalTransformers(transformers []string) ([]*r
}
if err = ra.AppendAll(rm); err != nil {
return nil, errors.Wrapf(err, "configuring external transformer")
return nil, errors.WrapPrefixf(err, "configuring external transformer")
}
}
ra, err := kt.accumulateResources(ra, transformerPaths)
@@ -415,7 +424,7 @@ func (kt *KustTarget) accumulateResources(
if kusterr.IsMalformedYAMLError(errF) { // Some error occurred while tyring to decode YAML file
return nil, errF
}
return nil, errors.Wrapf(
return nil, errors.WrapPrefixf(
err, "accumulation err='%s'", errF.Error())
}
// store the origin, we'll need it later
@@ -432,7 +441,7 @@ func (kt *KustTarget) accumulateResources(
if kusterr.IsMalformedYAMLError(errF) { // Some error occurred while tyring to decode YAML file
return nil, errF
}
return nil, errors.Wrapf(
return nil, errors.WrapPrefixf(
err, "accumulation err='%s'", errF.Error())
}
}
@@ -474,7 +483,7 @@ func (kt *KustTarget) accumulateDirectory(
subKt := NewKustTarget(ldr, kt.validator, kt.rFactory, kt.pLdr)
err := subKt.Load()
if err != nil {
return nil, errors.Wrapf(
return nil, errors.WrapPrefixf(
err, "couldn't make target for path '%s'", ldr.Root())
}
subKt.kustomization.BuildMetadata = kt.kustomization.BuildMetadata
@@ -509,12 +518,12 @@ func (kt *KustTarget) accumulateDirectory(
subRa, err = subKt.AccumulateTarget()
}
if err != nil {
return nil, errors.Wrapf(
return nil, errors.WrapPrefixf(
err, "recursed accumulation of path '%s'", ldr.Root())
}
err = ra.MergeAccumulator(subRa)
if err != nil {
return nil, errors.Wrapf(
return nil, errors.WrapPrefixf(
err, "recursed merging from path '%s'", ldr.Root())
}
return ra, nil
@@ -524,21 +533,21 @@ func (kt *KustTarget) accumulateFile(
ra *accumulator.ResAccumulator, path string) error {
resources, err := kt.rFactory.FromFile(kt.ldr, path)
if err != nil {
return errors.Wrapf(err, "accumulating resources from '%s'", path)
return errors.WrapPrefixf(err, "accumulating resources from '%s'", path)
}
if kt.origin != nil {
originAnno, err := kt.origin.Append(path).String()
if err != nil {
return errors.Wrapf(err, "cannot add path annotation for '%s'", path)
return errors.WrapPrefixf(err, "cannot add path annotation for '%s'", path)
}
err = resources.AnnotateAll(utils.OriginAnnotationKey, originAnno)
if err != nil || originAnno == "" {
return errors.Wrapf(err, "cannot add path annotation for '%s'", path)
return errors.WrapPrefixf(err, "cannot add path annotation for '%s'", path)
}
}
err = ra.AppendAll(resources)
if err != nil {
return errors.Wrapf(err, "merging resources from '%s'", path)
return errors.WrapPrefixf(err, "merging resources from '%s'", path)
}
return nil
}
@@ -549,7 +558,7 @@ func (kt *KustTarget) configureBuiltinPlugin(
if c != nil {
y, err = yaml.Marshal(c)
if err != nil {
return errors.Wrapf(
return errors.WrapPrefixf(
err, "builtin %s marshal", bpt)
}
}
@@ -558,7 +567,7 @@ func (kt *KustTarget) configureBuiltinPlugin(
kt.ldr, kt.validator, kt.rFactory, kt.pLdr.Config()),
y)
if err != nil {
return errors.Wrapf(
return errors.WrapPrefixf(
err, "trouble configuring builtin %s with config: `\n%s`", bpt, string(y))
}
return nil

View File

@@ -7,12 +7,12 @@ import (
"fmt"
"path/filepath"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
@@ -286,11 +286,11 @@ var transformerConfigurators = map[builtinhelpers.BuiltinPluginType]func(
if label.IncludeSelectors {
fss, err = fss.MergeAll(tc.CommonLabels)
} else {
// merge spec/template/metadata fieldSpec if includeTemplate flag is true
// merge spec/template/metadata fieldSpecs if includeTemplate flag is true
if label.IncludeTemplates {
fss, err = fss.MergeOne(types.FieldSpec{Path: "spec/template/metadata/labels", CreateIfNotPresent: false})
fss, err = fss.MergeAll(tc.TemplateLabels)
if err != nil {
return nil, errors.Wrap(err, "failed to merge template fieldSpec")
return nil, errors.WrapPrefixf(err, "failed to merge template fieldSpec")
}
}
// only add to metadata by default

View File

@@ -7,7 +7,7 @@ import (
"fmt"
"time"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/kyaml/errors"
)
type errTimeOut struct {
@@ -24,13 +24,6 @@ func (e errTimeOut) Error() string {
}
func IsErrTimeout(err error) bool {
if err == nil {
return false
}
_, ok := err.(errTimeOut)
if ok {
return true
}
_, ok = errors.Cause(err).(errTimeOut)
return ok
e := &errTimeOut{}
return errors.As(err, &e)
}

View File

@@ -35,7 +35,10 @@ func PrevIds(n *yaml.RNode) ([]resid.ResId, error) {
var ids []resid.ResId
// TODO: merge previous names and namespaces into one list of
// pairs on one annotation so there is no chance of error
annotations := n.GetAnnotations()
annotations := n.GetAnnotations(
BuildAnnotationPreviousNames,
BuildAnnotationPreviousNamespaces,
BuildAnnotationPreviousKinds)
if _, ok := annotations[BuildAnnotationPreviousNames]; !ok {
return nil, nil
}
@@ -49,12 +52,10 @@ func PrevIds(n *yaml.RNode) ([]resid.ResId, error) {
"number of previous namespaces, " +
"number of previous kinds not equal")
}
apiVersion := n.GetApiVersion()
group, version := resid.ParseGroupVersion(apiVersion)
ids = make([]resid.ResId, 0, len(names))
for i := range names {
meta, err := n.GetMeta()
if err != nil {
return nil, err
}
group, version := resid.ParseGroupVersion(meta.APIVersion)
gvk := resid.Gvk{
Group: group,
Version: version,