update modules kustomize add helm
Signed-off-by: LiHui <andrewli@yunify.com>
This commit is contained in:
201
vendor/sigs.k8s.io/kustomize/api/LICENSE
generated
vendored
Normal file
201
vendor/sigs.k8s.io/kustomize/api/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
232
vendor/sigs.k8s.io/kustomize/api/resid/gvk.go
generated
vendored
Normal file
232
vendor/sigs.k8s.io/kustomize/api/resid/gvk.go
generated
vendored
Normal file
@@ -0,0 +1,232 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package resid
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/kyaml/openapi"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
// Gvk identifies a Kubernetes API type.
|
||||
// https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
|
||||
type Gvk struct {
|
||||
Group string `json:"group,omitempty" yaml:"group,omitempty"`
|
||||
Version string `json:"version,omitempty" yaml:"version,omitempty"`
|
||||
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
|
||||
}
|
||||
|
||||
// FromKind makes a Gvk with only the kind specified.
|
||||
func FromKind(k string) Gvk {
|
||||
return Gvk{
|
||||
Kind: k,
|
||||
}
|
||||
}
|
||||
|
||||
// ParseGroupVersion parses a KRM metadata apiVersion field.
|
||||
func ParseGroupVersion(apiVersion string) (group, version string) {
|
||||
if i := strings.Index(apiVersion, "/"); i > -1 {
|
||||
return apiVersion[:i], apiVersion[i+1:]
|
||||
}
|
||||
return "", apiVersion
|
||||
}
|
||||
|
||||
// GvkFromString makes a Gvk from the output of Gvk.String().
|
||||
func GvkFromString(s string) Gvk {
|
||||
values := strings.Split(s, fieldSep)
|
||||
if len(values) != 3 {
|
||||
// ...then the string didn't come from Gvk.String().
|
||||
return Gvk{
|
||||
Group: noGroup,
|
||||
Version: noVersion,
|
||||
Kind: noKind,
|
||||
}
|
||||
}
|
||||
g := values[0]
|
||||
if g == noGroup {
|
||||
g = ""
|
||||
}
|
||||
v := values[1]
|
||||
if v == noVersion {
|
||||
v = ""
|
||||
}
|
||||
k := values[2]
|
||||
if k == noKind {
|
||||
k = ""
|
||||
}
|
||||
return Gvk{
|
||||
Group: g,
|
||||
Version: v,
|
||||
Kind: k,
|
||||
}
|
||||
}
|
||||
|
||||
// Values that are brief but meaningful in logs.
|
||||
const (
|
||||
noGroup = "~G"
|
||||
noVersion = "~V"
|
||||
noKind = "~K"
|
||||
fieldSep = "_"
|
||||
)
|
||||
|
||||
// String returns a string representation of the GVK.
|
||||
func (x Gvk) String() string {
|
||||
g := x.Group
|
||||
if g == "" {
|
||||
g = noGroup
|
||||
}
|
||||
v := x.Version
|
||||
if v == "" {
|
||||
v = noVersion
|
||||
}
|
||||
k := x.Kind
|
||||
if k == "" {
|
||||
k = noKind
|
||||
}
|
||||
return strings.Join([]string{g, v, k}, fieldSep)
|
||||
}
|
||||
|
||||
// ApiVersion returns the combination of Group and Version
|
||||
func (x Gvk) ApiVersion() string {
|
||||
if x.Group == "" {
|
||||
return x.Version
|
||||
}
|
||||
return x.Group + "/" + x.Version
|
||||
}
|
||||
|
||||
// StringWoEmptyField returns a string representation of the GVK. Non-exist
|
||||
// fields will be omitted.
|
||||
func (x Gvk) StringWoEmptyField() string {
|
||||
var s []string
|
||||
if x.Group != "" {
|
||||
s = append(s, x.Group)
|
||||
}
|
||||
if x.Version != "" {
|
||||
s = append(s, x.Version)
|
||||
}
|
||||
if x.Kind != "" {
|
||||
s = append(s, x.Kind)
|
||||
}
|
||||
return strings.Join(s, fieldSep)
|
||||
}
|
||||
|
||||
// Equals returns true if the Gvk's have equal fields.
|
||||
func (x Gvk) Equals(o Gvk) bool {
|
||||
return x.Group == o.Group && x.Version == o.Version && x.Kind == o.Kind
|
||||
}
|
||||
|
||||
// An attempt to order things to help k8s, e.g.
|
||||
// a Service should come before things that refer to it.
|
||||
// Namespace should be first.
|
||||
// In some cases order just specified to provide determinism.
|
||||
var orderFirst = []string{
|
||||
"Namespace",
|
||||
"ResourceQuota",
|
||||
"StorageClass",
|
||||
"CustomResourceDefinition",
|
||||
"ServiceAccount",
|
||||
"PodSecurityPolicy",
|
||||
"Role",
|
||||
"ClusterRole",
|
||||
"RoleBinding",
|
||||
"ClusterRoleBinding",
|
||||
"ConfigMap",
|
||||
"Secret",
|
||||
"Endpoints",
|
||||
"Service",
|
||||
"LimitRange",
|
||||
"PriorityClass",
|
||||
"PersistentVolume",
|
||||
"PersistentVolumeClaim",
|
||||
"Deployment",
|
||||
"StatefulSet",
|
||||
"CronJob",
|
||||
"PodDisruptionBudget",
|
||||
}
|
||||
var orderLast = []string{
|
||||
"MutatingWebhookConfiguration",
|
||||
"ValidatingWebhookConfiguration",
|
||||
}
|
||||
var typeOrders = func() map[string]int {
|
||||
m := map[string]int{}
|
||||
for i, n := range orderFirst {
|
||||
m[n] = -len(orderFirst) + i
|
||||
}
|
||||
for i, n := range orderLast {
|
||||
m[n] = 1 + i
|
||||
}
|
||||
return m
|
||||
}()
|
||||
|
||||
// IsLessThan returns true if self is less than the argument.
|
||||
func (x Gvk) IsLessThan(o Gvk) bool {
|
||||
indexI := typeOrders[x.Kind]
|
||||
indexJ := typeOrders[o.Kind]
|
||||
if indexI != indexJ {
|
||||
return indexI < indexJ
|
||||
}
|
||||
return x.String() < o.String()
|
||||
}
|
||||
|
||||
// IsSelected returns true if `selector` selects `x`; otherwise, false.
|
||||
// If `selector` and `x` are the same, return true.
|
||||
// If `selector` is nil, it is considered a wildcard match, returning true.
|
||||
// If selector fields are empty, they are considered wildcards matching
|
||||
// anything in the corresponding fields, e.g.
|
||||
//
|
||||
// this item:
|
||||
// <Group: "extensions", Version: "v1beta1", Kind: "Deployment">
|
||||
//
|
||||
// is selected by
|
||||
// <Group: "", Version: "", Kind: "Deployment">
|
||||
//
|
||||
// but rejected by
|
||||
// <Group: "apps", Version: "", Kind: "Deployment">
|
||||
//
|
||||
func (x Gvk) IsSelected(selector *Gvk) bool {
|
||||
if selector == nil {
|
||||
return true
|
||||
}
|
||||
if len(selector.Group) > 0 {
|
||||
if x.Group != selector.Group {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if len(selector.Version) > 0 {
|
||||
if x.Version != selector.Version {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if len(selector.Kind) > 0 {
|
||||
if x.Kind != selector.Kind {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// toKyamlTypeMeta returns a yaml.TypeMeta from x's information.
|
||||
func (x Gvk) toKyamlTypeMeta() yaml.TypeMeta {
|
||||
var apiVersion strings.Builder
|
||||
if x.Group != "" {
|
||||
apiVersion.WriteString(x.Group)
|
||||
apiVersion.WriteString("/")
|
||||
}
|
||||
apiVersion.WriteString(x.Version)
|
||||
return yaml.TypeMeta{
|
||||
APIVersion: apiVersion.String(),
|
||||
Kind: x.Kind,
|
||||
}
|
||||
}
|
||||
|
||||
// IsNamespaceableKind returns true if x is a namespaceable Gvk,
|
||||
// e.g. instances of Pod and Deployment are namespaceable,
|
||||
// but instances of Node and Namespace are not namespaceable.
|
||||
// Alternative name for this method: IsNotClusterScoped.
|
||||
// Implements https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/#not-all-objects-are-in-a-namespace
|
||||
func (x Gvk) IsNamespaceableKind() bool {
|
||||
isNamespaceScoped, found := openapi.IsNamespaceScoped(x.toKyamlTypeMeta())
|
||||
return !found || isNamespaceScoped
|
||||
}
|
||||
127
vendor/sigs.k8s.io/kustomize/api/resid/resid.go
generated
vendored
Normal file
127
vendor/sigs.k8s.io/kustomize/api/resid/resid.go
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package resid
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ResId is an identifier of a k8s resource object.
|
||||
type ResId struct {
|
||||
// Gvk of the resource.
|
||||
Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
|
||||
// Name of the resource before transformation.
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
|
||||
// Namespace the resource belongs to.
|
||||
// An untransformed resource has no namespace.
|
||||
// A fully transformed resource has the namespace
|
||||
// from the top most overlay.
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
// NewResIdWithNamespace creates new ResId
|
||||
// in a given namespace.
|
||||
func NewResIdWithNamespace(k Gvk, n, ns string) ResId {
|
||||
return ResId{Gvk: k, Name: n, Namespace: ns}
|
||||
}
|
||||
|
||||
// NewResId creates new ResId.
|
||||
func NewResId(k Gvk, n string) ResId {
|
||||
return ResId{Gvk: k, Name: n}
|
||||
}
|
||||
|
||||
// NewResIdKindOnly creates a new ResId.
|
||||
func NewResIdKindOnly(k string, n string) ResId {
|
||||
return ResId{Gvk: FromKind(k), Name: n}
|
||||
}
|
||||
|
||||
const (
|
||||
noNamespace = "~X"
|
||||
noName = "~N"
|
||||
separator = "|"
|
||||
TotallyNotANamespace = "_non_namespaceable_"
|
||||
DefaultNamespace = "default"
|
||||
)
|
||||
|
||||
// String of ResId based on GVK, name and prefix
|
||||
func (id ResId) String() string {
|
||||
ns := id.Namespace
|
||||
if ns == "" {
|
||||
ns = noNamespace
|
||||
}
|
||||
nm := id.Name
|
||||
if nm == "" {
|
||||
nm = noName
|
||||
}
|
||||
return strings.Join(
|
||||
[]string{id.Gvk.String(), ns, nm}, separator)
|
||||
}
|
||||
|
||||
func FromString(s string) ResId {
|
||||
values := strings.Split(s, separator)
|
||||
g := GvkFromString(values[0])
|
||||
|
||||
ns := values[1]
|
||||
if ns == noNamespace {
|
||||
ns = ""
|
||||
}
|
||||
nm := values[2]
|
||||
if nm == noName {
|
||||
nm = ""
|
||||
}
|
||||
return ResId{
|
||||
Gvk: g,
|
||||
Namespace: ns,
|
||||
Name: nm,
|
||||
}
|
||||
}
|
||||
|
||||
// GvknString of ResId based on GVK and name
|
||||
func (id ResId) GvknString() string {
|
||||
return id.Gvk.String() + separator + id.Name
|
||||
}
|
||||
|
||||
// GvknEquals returns true if the other id matches
|
||||
// Group/Version/Kind/name.
|
||||
func (id ResId) GvknEquals(o ResId) bool {
|
||||
return id.Name == o.Name && id.Gvk.Equals(o.Gvk)
|
||||
}
|
||||
|
||||
// Equals returns true if the other id matches
|
||||
// namespace/Group/Version/Kind/name.
|
||||
func (id ResId) Equals(o ResId) bool {
|
||||
return id.IsNsEquals(o) && id.GvknEquals(o)
|
||||
}
|
||||
|
||||
// IsNsEquals returns true if the id is in
|
||||
// the same effective namespace.
|
||||
func (id ResId) IsNsEquals(o ResId) bool {
|
||||
return id.EffectiveNamespace() == o.EffectiveNamespace()
|
||||
}
|
||||
|
||||
// IsInDefaultNs returns true if id is a namespaceable
|
||||
// ResId and the Namespace is either not set or set
|
||||
// to DefaultNamespace.
|
||||
func (id ResId) IsInDefaultNs() bool {
|
||||
return id.IsNamespaceableKind() && id.isPutativelyDefaultNs()
|
||||
}
|
||||
|
||||
func (id ResId) isPutativelyDefaultNs() bool {
|
||||
return id.Namespace == "" || id.Namespace == DefaultNamespace
|
||||
}
|
||||
|
||||
// EffectiveNamespace returns a non-ambiguous, non-empty
|
||||
// namespace for use in reporting and equality tests.
|
||||
func (id ResId) EffectiveNamespace() string {
|
||||
// The order of these checks matters.
|
||||
if !id.IsNamespaceableKind() {
|
||||
return TotallyNotANamespace
|
||||
}
|
||||
if id.isPutativelyDefaultNs() {
|
||||
return DefaultNamespace
|
||||
}
|
||||
return id.Namespace
|
||||
}
|
||||
25
vendor/sigs.k8s.io/kustomize/api/types/builtinpluginloadingoptions_string.go
generated
vendored
Normal file
25
vendor/sigs.k8s.io/kustomize/api/types/builtinpluginloadingoptions_string.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// Code generated by "stringer -type=BuiltinPluginLoadingOptions"; DO NOT EDIT.
|
||||
|
||||
package types
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[BploUndefined-0]
|
||||
_ = x[BploUseStaticallyLinked-1]
|
||||
_ = x[BploLoadFromFileSys-2]
|
||||
}
|
||||
|
||||
const _BuiltinPluginLoadingOptions_name = "BploUndefinedBploUseStaticallyLinkedBploLoadFromFileSys"
|
||||
|
||||
var _BuiltinPluginLoadingOptions_index = [...]uint8{0, 13, 36, 55}
|
||||
|
||||
func (i BuiltinPluginLoadingOptions) String() string {
|
||||
if i < 0 || i >= BuiltinPluginLoadingOptions(len(_BuiltinPluginLoadingOptions_index)-1) {
|
||||
return "BuiltinPluginLoadingOptions(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _BuiltinPluginLoadingOptions_name[_BuiltinPluginLoadingOptions_index[i]:_BuiltinPluginLoadingOptions_index[i+1]]
|
||||
}
|
||||
10
vendor/sigs.k8s.io/kustomize/api/types/configmapargs.go
generated
vendored
Normal file
10
vendor/sigs.k8s.io/kustomize/api/types/configmapargs.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// ConfigMapArgs contains the metadata of how to generate a configmap.
|
||||
type ConfigMapArgs struct {
|
||||
// GeneratorArgs for the configmap.
|
||||
GeneratorArgs `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
}
|
||||
9
vendor/sigs.k8s.io/kustomize/api/types/doc.go
generated
vendored
Normal file
9
vendor/sigs.k8s.io/kustomize/api/types/doc.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package types holds the definition of the kustomization struct and
|
||||
// supporting structs. It's the k8s API conformant object that describes
|
||||
// a set of generation and transformation operations to create and/or
|
||||
// modify k8s resources.
|
||||
// A kustomization file is a serialization of this struct.
|
||||
package types
|
||||
33
vendor/sigs.k8s.io/kustomize/api/types/erronlybuiltinpluginsallowed.go
generated
vendored
Normal file
33
vendor/sigs.k8s.io/kustomize/api/types/erronlybuiltinpluginsallowed.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type errOnlyBuiltinPluginsAllowed struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (e *errOnlyBuiltinPluginsAllowed) Error() string {
|
||||
return fmt.Sprintf(
|
||||
"external plugins disabled; unable to load external plugin '%s'",
|
||||
e.name)
|
||||
}
|
||||
|
||||
func NewErrOnlyBuiltinPluginsAllowed(n string) *errOnlyBuiltinPluginsAllowed {
|
||||
return &errOnlyBuiltinPluginsAllowed{name: n}
|
||||
}
|
||||
|
||||
func IsErrOnlyBuiltinPluginsAllowed(err error) bool {
|
||||
_, ok := err.(*errOnlyBuiltinPluginsAllowed)
|
||||
if ok {
|
||||
return true
|
||||
}
|
||||
_, ok = errors.Cause(err).(*errOnlyBuiltinPluginsAllowed)
|
||||
return ok
|
||||
}
|
||||
40
vendor/sigs.k8s.io/kustomize/api/types/errunabletofind.go
generated
vendored
Normal file
40
vendor/sigs.k8s.io/kustomize/api/types/errunabletofind.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type errUnableToFind struct {
|
||||
// What are we unable to find?
|
||||
what string
|
||||
// What things did we try?
|
||||
attempts []Pair
|
||||
}
|
||||
|
||||
func (e *errUnableToFind) Error() string {
|
||||
var m []string
|
||||
for _, p := range e.attempts {
|
||||
m = append(m, "('"+p.Value+"'; "+p.Key+")")
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
"unable to find %s - tried: %s", e.what, strings.Join(m, ", "))
|
||||
}
|
||||
|
||||
func NewErrUnableToFind(w string, a []Pair) *errUnableToFind {
|
||||
return &errUnableToFind{what: w, attempts: a}
|
||||
}
|
||||
|
||||
func IsErrUnableToFind(err error) bool {
|
||||
_, ok := err.(*errUnableToFind)
|
||||
if ok {
|
||||
return true
|
||||
}
|
||||
_, ok = errors.Cause(err).(*errUnableToFind)
|
||||
return ok
|
||||
}
|
||||
91
vendor/sigs.k8s.io/kustomize/api/types/fieldspec.go
generated
vendored
Normal file
91
vendor/sigs.k8s.io/kustomize/api/types/fieldspec.go
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
)
|
||||
|
||||
// FieldSpec completely specifies a kustomizable field in a k8s API object.
|
||||
// It helps define the operands of transformations.
|
||||
//
|
||||
// For example, a directive to add a common label to objects
|
||||
// will need to know that a 'Deployment' object (in API group
|
||||
// 'apps', any version) can have labels at field path
|
||||
// 'spec/template/metadata/labels', and further that it is OK
|
||||
// (or not OK) to add that field path to the object if the
|
||||
// field path doesn't exist already.
|
||||
//
|
||||
// This would look like
|
||||
// {
|
||||
// group: apps
|
||||
// kind: Deployment
|
||||
// path: spec/template/metadata/labels
|
||||
// create: true
|
||||
// }
|
||||
type FieldSpec struct {
|
||||
resid.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
CreateIfNotPresent bool `json:"create,omitempty" yaml:"create,omitempty"`
|
||||
}
|
||||
|
||||
func (fs FieldSpec) String() string {
|
||||
return fmt.Sprintf(
|
||||
"%s:%v:%s", fs.Gvk.String(), fs.CreateIfNotPresent, fs.Path)
|
||||
}
|
||||
|
||||
// If true, the primary key is the same, but other fields might not be.
|
||||
func (fs FieldSpec) effectivelyEquals(other FieldSpec) bool {
|
||||
return fs.IsSelected(&other.Gvk) && fs.Path == other.Path
|
||||
}
|
||||
|
||||
type FsSlice []FieldSpec
|
||||
|
||||
func (s FsSlice) Len() int { return len(s) }
|
||||
func (s FsSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
func (s FsSlice) Less(i, j int) bool {
|
||||
return s[i].Gvk.IsLessThan(s[j].Gvk)
|
||||
}
|
||||
|
||||
// MergeAll merges the argument into this, returning the result.
|
||||
// Items already present are ignored.
|
||||
// Items that conflict (primary key matches, but remain data differs)
|
||||
// result in an error.
|
||||
func (s FsSlice) MergeAll(incoming FsSlice) (result FsSlice, err error) {
|
||||
result = s
|
||||
for _, x := range incoming {
|
||||
result, err = result.MergeOne(x)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// MergeOne merges the argument into this, returning the result.
|
||||
// If the item's primary key is already present, and there are no
|
||||
// conflicts, it is ignored (we don't want duplicates).
|
||||
// If there is a conflict, the merge fails.
|
||||
func (s FsSlice) MergeOne(x FieldSpec) (FsSlice, error) {
|
||||
i := s.index(x)
|
||||
if i > -1 {
|
||||
// It's already there.
|
||||
if s[i].CreateIfNotPresent != x.CreateIfNotPresent {
|
||||
return nil, fmt.Errorf("conflicting fieldspecs")
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
return append(s, x), nil
|
||||
}
|
||||
|
||||
func (s FsSlice) index(fs FieldSpec) int {
|
||||
for i, x := range s {
|
||||
if x.effectivelyEquals(fs) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
54
vendor/sigs.k8s.io/kustomize/api/types/fix.go
generated
vendored
Normal file
54
vendor/sigs.k8s.io/kustomize/api/types/fix.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// FixKustomizationPreUnmarshalling modifies the raw data
|
||||
// before marshalling - e.g. changes old field names to
|
||||
// new field names.
|
||||
func FixKustomizationPreUnmarshalling(data []byte) ([]byte, error) {
|
||||
deprecatedFieldsMap := map[string]string{
|
||||
"imageTags:": "images:",
|
||||
}
|
||||
for oldname, newname := range deprecatedFieldsMap {
|
||||
pattern := regexp.MustCompile(oldname)
|
||||
data = pattern.ReplaceAll(data, []byte(newname))
|
||||
}
|
||||
doLegacy, err := useLegacyPatch(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if doLegacy {
|
||||
pattern := regexp.MustCompile("patches:")
|
||||
data = pattern.ReplaceAll(data, []byte("patchesStrategicMerge:"))
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func useLegacyPatch(data []byte) (bool, error) {
|
||||
found := false
|
||||
var object map[string]interface{}
|
||||
err := yaml.Unmarshal(data, &object)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if rawPatches, ok := object["patches"]; ok {
|
||||
patches, ok := rawPatches.([]interface{})
|
||||
if !ok {
|
||||
return false, err
|
||||
}
|
||||
for _, p := range patches {
|
||||
_, ok := p.(string)
|
||||
if ok {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return found, nil
|
||||
}
|
||||
46
vendor/sigs.k8s.io/kustomize/api/types/genargs.go
generated
vendored
Normal file
46
vendor/sigs.k8s.io/kustomize/api/types/genargs.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GenArgs is a facade over GeneratorArgs, exposing a few readonly properties.
|
||||
type GenArgs struct {
|
||||
args *GeneratorArgs
|
||||
}
|
||||
|
||||
// NewGenArgs returns a new instance of GenArgs.
|
||||
func NewGenArgs(args *GeneratorArgs) *GenArgs {
|
||||
return &GenArgs{args: args}
|
||||
}
|
||||
|
||||
func (g *GenArgs) String() string {
|
||||
if g == nil {
|
||||
return "{nilGenArgs}"
|
||||
}
|
||||
return "{" +
|
||||
strings.Join([]string{
|
||||
"nsfx:" + strconv.FormatBool(g.ShouldAddHashSuffixToName()),
|
||||
"beh:" + g.Behavior().String()},
|
||||
",") +
|
||||
"}"
|
||||
}
|
||||
|
||||
// ShouldAddHashSuffixToName returns true if a resource
|
||||
// content hash should be appended to the name of the resource.
|
||||
func (g *GenArgs) ShouldAddHashSuffixToName() bool {
|
||||
return g.args != nil &&
|
||||
(g.args.Options == nil || !g.args.Options.DisableNameSuffixHash)
|
||||
}
|
||||
|
||||
// Behavior returns Behavior field of GeneratorArgs
|
||||
func (g *GenArgs) Behavior() GenerationBehavior {
|
||||
if g.args == nil {
|
||||
return BehaviorUnspecified
|
||||
}
|
||||
return NewGenerationBehavior(g.args.Behavior)
|
||||
}
|
||||
46
vendor/sigs.k8s.io/kustomize/api/types/generationbehavior.go
generated
vendored
Normal file
46
vendor/sigs.k8s.io/kustomize/api/types/generationbehavior.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// GenerationBehavior specifies generation behavior of configmaps, secrets and maybe other resources.
|
||||
type GenerationBehavior int
|
||||
|
||||
const (
|
||||
// BehaviorUnspecified is an Unspecified behavior; typically treated as a Create.
|
||||
BehaviorUnspecified GenerationBehavior = iota
|
||||
// BehaviorCreate makes a new resource.
|
||||
BehaviorCreate
|
||||
// BehaviorReplace replaces a resource.
|
||||
BehaviorReplace
|
||||
// BehaviorMerge attempts to merge a new resource with an existing resource.
|
||||
BehaviorMerge
|
||||
)
|
||||
|
||||
// String converts a GenerationBehavior to a string.
|
||||
func (b GenerationBehavior) String() string {
|
||||
switch b {
|
||||
case BehaviorReplace:
|
||||
return "replace"
|
||||
case BehaviorMerge:
|
||||
return "merge"
|
||||
case BehaviorCreate:
|
||||
return "create"
|
||||
default:
|
||||
return "unspecified"
|
||||
}
|
||||
}
|
||||
|
||||
// NewGenerationBehavior converts a string to a GenerationBehavior.
|
||||
func NewGenerationBehavior(s string) GenerationBehavior {
|
||||
switch s {
|
||||
case "replace":
|
||||
return BehaviorReplace
|
||||
case "merge":
|
||||
return BehaviorMerge
|
||||
case "create":
|
||||
return BehaviorCreate
|
||||
default:
|
||||
return BehaviorUnspecified
|
||||
}
|
||||
}
|
||||
27
vendor/sigs.k8s.io/kustomize/api/types/generatorargs.go
generated
vendored
Normal file
27
vendor/sigs.k8s.io/kustomize/api/types/generatorargs.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// GeneratorArgs contains arguments common to ConfigMap and Secret generators.
|
||||
type GeneratorArgs struct {
|
||||
// Namespace for the configmap, optional
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
|
||||
// Name - actually the partial name - of the generated resource.
|
||||
// The full name ends up being something like
|
||||
// NamePrefix + this.Name + hash(content of generated resource).
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
|
||||
// Behavior of generated resource, must be one of:
|
||||
// 'create': create a new one
|
||||
// 'replace': replace the existing one
|
||||
// 'merge': merge with the existing one
|
||||
Behavior string `json:"behavior,omitempty" yaml:"behavior,omitempty"`
|
||||
|
||||
// KvPairSources for the generator.
|
||||
KvPairSources `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
|
||||
// Local overrides to global generatorOptions field.
|
||||
Options *GeneratorOptions `json:"options,omitempty" yaml:"options,omitempty"`
|
||||
}
|
||||
70
vendor/sigs.k8s.io/kustomize/api/types/generatoroptions.go
generated
vendored
Normal file
70
vendor/sigs.k8s.io/kustomize/api/types/generatoroptions.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// GeneratorOptions modify behavior of all ConfigMap and Secret generators.
|
||||
type GeneratorOptions struct {
|
||||
// Labels to add to all generated resources.
|
||||
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
|
||||
|
||||
// Annotations to add to all generated resources.
|
||||
Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
|
||||
|
||||
// DisableNameSuffixHash if true disables the default behavior of adding a
|
||||
// suffix to the names of generated resources that is a hash of the
|
||||
// resource contents.
|
||||
DisableNameSuffixHash bool `json:"disableNameSuffixHash,omitempty" yaml:"disableNameSuffixHash,omitempty"`
|
||||
}
|
||||
|
||||
// MergeGlobalOptionsIntoLocal merges two instances of GeneratorOptions.
|
||||
// Values in the first 'local' argument cannot be overridden by the second
|
||||
// 'global' argument, except in the case of booleans.
|
||||
//
|
||||
// With booleans, there's no way to distinguish an 'intentional'
|
||||
// false from 'default' false. So the rule is, if the global value
|
||||
// of the value of a boolean is true, i.e. disable, it trumps the
|
||||
// local value. If the global value is false, then the local value is
|
||||
// respected. Bottom line: a local false cannot override a global true.
|
||||
//
|
||||
// boolean fields are always a bad idea; should always use enums instead.
|
||||
func MergeGlobalOptionsIntoLocal(
|
||||
localOpts *GeneratorOptions,
|
||||
globalOpts *GeneratorOptions) *GeneratorOptions {
|
||||
if globalOpts == nil {
|
||||
return localOpts
|
||||
}
|
||||
if localOpts == nil {
|
||||
localOpts = &GeneratorOptions{}
|
||||
}
|
||||
overrideMap(&localOpts.Labels, globalOpts.Labels)
|
||||
overrideMap(&localOpts.Annotations, globalOpts.Annotations)
|
||||
if globalOpts.DisableNameSuffixHash {
|
||||
localOpts.DisableNameSuffixHash = true
|
||||
}
|
||||
return localOpts
|
||||
}
|
||||
|
||||
func overrideMap(localMap *map[string]string, globalMap map[string]string) {
|
||||
if *localMap == nil {
|
||||
if globalMap != nil {
|
||||
*localMap = CopyMap(globalMap)
|
||||
}
|
||||
return
|
||||
}
|
||||
for k, v := range globalMap {
|
||||
_, ok := (*localMap)[k]
|
||||
if !ok {
|
||||
(*localMap)[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CopyMap copies a map.
|
||||
func CopyMap(in map[string]string) map[string]string {
|
||||
out := make(map[string]string)
|
||||
for k, v := range in {
|
||||
out[k] = v
|
||||
}
|
||||
return out
|
||||
}
|
||||
114
vendor/sigs.k8s.io/kustomize/api/types/helmchartargs.go
generated
vendored
Normal file
114
vendor/sigs.k8s.io/kustomize/api/types/helmchartargs.go
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
type HelmGlobals struct {
|
||||
// ChartHome is a file path, relative to the kustomization root,
|
||||
// to a directory containing a subdirectory for each chart to be
|
||||
// included in the kustomization.
|
||||
// The default value of this field is "charts".
|
||||
// So, for example, kustomize looks for the minecraft chart
|
||||
// at {kustomizationRoot}/{ChartHome}/minecraft.
|
||||
// If the chart is there at build time, kustomize will use it as found,
|
||||
// and not check version numbers or dates.
|
||||
// If the chart is not there, kustomize will attempt to pull it
|
||||
// using the version number specified in the kustomization file,
|
||||
// and put it there. To suppress the pull attempt, simply assure
|
||||
// that the chart is already there.
|
||||
ChartHome string `json:"chartHome,omitempty" yaml:"chartHome,omitempty"`
|
||||
|
||||
// ConfigHome defines a value that kustomize should pass to helm via
|
||||
// the HELM_CONFIG_HOME environment variable. kustomize doesn't attempt
|
||||
// to read or write this directory.
|
||||
// If omitted, {tmpDir}/helm is used, where {tmpDir} is some temporary
|
||||
// directory created by kustomize for the benefit of helm.
|
||||
// Likewise, kustomize sets
|
||||
// HELM_CACHE_HOME={ConfigHome}/.cache
|
||||
// HELM_DATA_HOME={ConfigHome}/.data
|
||||
// for the helm subprocess.
|
||||
ConfigHome string `json:"configHome,omitempty" yaml:"configHome,omitempty"`
|
||||
}
|
||||
|
||||
type HelmChart struct {
|
||||
// Name is the name of the chart, e.g. 'minecraft'.
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
|
||||
// Version is the version of the chart, e.g. '3.1.3'
|
||||
Version string `json:"version,omitempty" yaml:"version,omitempty"`
|
||||
|
||||
// Repo is a URL locating the chart on the internet.
|
||||
// This is the argument to helm's `--repo` flag, e.g.
|
||||
// `https://itzg.github.io/minecraft-server-charts`.
|
||||
Repo string `json:"repo,omitempty" yaml:"repo,omitempty"`
|
||||
|
||||
// ReleaseName replaces RELEASE-NAME in chart template output,
|
||||
// making a particular inflation of a chart unique with respect to
|
||||
// other inflations of the same chart in a cluster. It's the first
|
||||
// argument to the helm `install` and `template` commands, i.e.
|
||||
// helm install {RELEASE-NAME} {chartName}
|
||||
// helm template {RELEASE-NAME} {chartName}
|
||||
// If omitted, the flag --generate-name is passed to 'helm template'.
|
||||
ReleaseName string `json:"releaseName,omitempty" yaml:"releaseName,omitempty"`
|
||||
|
||||
// ValuesFile is local file path to a values file to use _instead of_
|
||||
// the default values that accompanied the chart.
|
||||
// The default values are in '{ChartHome}/{Name}/values.yaml'.
|
||||
ValuesFile string `json:"valuesFile,omitempty" yaml:"valuesFile,omitempty"`
|
||||
|
||||
// ValuesInline holds value mappings specified directly,
|
||||
// rather than in a separate file.
|
||||
ValuesInline map[string]interface{} `json:"valuesInline,omitempty" yaml:"valuesInline,omitempty"`
|
||||
|
||||
// ValuesMerge specifies how to treat ValuesInline with respect to Values.
|
||||
// Legal values: 'merge', 'override', 'replace'.
|
||||
// Defaults to 'override'.
|
||||
ValuesMerge string `json:"valuesMerge,omitempty" yaml:"valuesMerge,omitempty"`
|
||||
}
|
||||
|
||||
// HelmChartArgs contains arguments to helm.
|
||||
// Deprecated. Use HelmGlobals and HelmChart instead.
|
||||
type HelmChartArgs struct {
|
||||
ChartName string `json:"chartName,omitempty" yaml:"chartName,omitempty"`
|
||||
ChartVersion string `json:"chartVersion,omitempty" yaml:"chartVersion,omitempty"`
|
||||
ChartRepoURL string `json:"chartRepoUrl,omitempty" yaml:"chartRepoUrl,omitempty"`
|
||||
ChartHome string `json:"chartHome,omitempty" yaml:"chartHome,omitempty"`
|
||||
ChartRepoName string `json:"chartRepoName,omitempty" yaml:"chartRepoName,omitempty"`
|
||||
HelmBin string `json:"helmBin,omitempty" yaml:"helmBin,omitempty"`
|
||||
HelmHome string `json:"helmHome,omitempty" yaml:"helmHome,omitempty"`
|
||||
Values string `json:"values,omitempty" yaml:"values,omitempty"`
|
||||
ValuesLocal map[string]interface{} `json:"valuesLocal,omitempty" yaml:"valuesLocal,omitempty"`
|
||||
ValuesMerge string `json:"valuesMerge,omitempty" yaml:"valuesMerge,omitempty"`
|
||||
ReleaseName string `json:"releaseName,omitempty" yaml:"releaseName,omitempty"`
|
||||
ReleaseNamespace string `json:"releaseNamespace,omitempty" yaml:"releaseNamespace,omitempty"`
|
||||
ExtraArgs []string `json:"extraArgs,omitempty" yaml:"extraArgs,omitempty"`
|
||||
}
|
||||
|
||||
// SplitHelmParameters splits helm parameters into
|
||||
// per-chart params and global chart-independent parameters.
|
||||
func SplitHelmParameters(
|
||||
oldArgs []HelmChartArgs) (charts []HelmChart, globals HelmGlobals) {
|
||||
for _, old := range oldArgs {
|
||||
charts = append(charts, makeHelmChartFromHca(&old))
|
||||
if old.HelmHome != "" {
|
||||
// last non-empty wins
|
||||
globals.ConfigHome = old.HelmHome
|
||||
}
|
||||
if old.ChartHome != "" {
|
||||
// last non-empty wins
|
||||
globals.ChartHome = old.ChartHome
|
||||
}
|
||||
}
|
||||
return charts, globals
|
||||
}
|
||||
|
||||
func makeHelmChartFromHca(old *HelmChartArgs) (c HelmChart) {
|
||||
c.Name = old.ChartName
|
||||
c.Version = old.ChartVersion
|
||||
c.Repo = old.ChartRepoURL
|
||||
c.ValuesFile = old.Values
|
||||
c.ValuesInline = old.ValuesLocal
|
||||
c.ValuesMerge = old.ValuesMerge
|
||||
c.ReleaseName = old.ReleaseName
|
||||
return
|
||||
}
|
||||
21
vendor/sigs.k8s.io/kustomize/api/types/image.go
generated
vendored
Normal file
21
vendor/sigs.k8s.io/kustomize/api/types/image.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Image contains an image name, a new name, a new tag or digest,
|
||||
// which will replace the original name and tag.
|
||||
type Image struct {
|
||||
// Name is a tag-less image name.
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
|
||||
// NewName is the value used to replace the original name.
|
||||
NewName string `json:"newName,omitempty" yaml:"newName,omitempty"`
|
||||
|
||||
// NewTag is the value used to replace the original tag.
|
||||
NewTag string `json:"newTag,omitempty" yaml:"newTag,omitempty"`
|
||||
|
||||
// Digest is the value used to replace the original image tag.
|
||||
// If digest is present NewTag value is ignored.
|
||||
Digest string `json:"digest,omitempty" yaml:"digest,omitempty"`
|
||||
}
|
||||
16
vendor/sigs.k8s.io/kustomize/api/types/inventory.go
generated
vendored
Normal file
16
vendor/sigs.k8s.io/kustomize/api/types/inventory.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Inventory records all objects touched in a build operation.
|
||||
type Inventory struct {
|
||||
Type string `json:"type,omitempty" yaml:"type,omitempty"`
|
||||
ConfigMap NameArgs `json:"configMap,omitempty" yaml:"configMap,omitempty"`
|
||||
}
|
||||
|
||||
// NameArgs holds both namespace and name.
|
||||
type NameArgs struct {
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
}
|
||||
261
vendor/sigs.k8s.io/kustomize/api/types/kustomization.go
generated
vendored
Normal file
261
vendor/sigs.k8s.io/kustomize/api/types/kustomization.go
generated
vendored
Normal file
@@ -0,0 +1,261 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
const (
|
||||
KustomizationVersion = "kustomize.config.k8s.io/v1beta1"
|
||||
KustomizationKind = "Kustomization"
|
||||
ComponentVersion = "kustomize.config.k8s.io/v1alpha1"
|
||||
ComponentKind = "Component"
|
||||
MetadataNamespacePath = "metadata/namespace"
|
||||
)
|
||||
|
||||
// Kustomization holds the information needed to generate customized k8s api resources.
|
||||
type Kustomization struct {
|
||||
TypeMeta `json:",inline" yaml:",inline"`
|
||||
|
||||
// MetaData is a pointer to avoid marshalling empty struct
|
||||
MetaData *ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||
|
||||
// OpenAPI contains information about what kubernetes schema to use.
|
||||
OpenAPI map[string]string `json:"openapi,omitempty" yaml:"openapi,omitempty"`
|
||||
|
||||
//
|
||||
// Operators - what kustomize can do.
|
||||
//
|
||||
|
||||
// NamePrefix will prefix the names of all resources mentioned in the kustomization
|
||||
// file including generated configmaps and secrets.
|
||||
NamePrefix string `json:"namePrefix,omitempty" yaml:"namePrefix,omitempty"`
|
||||
|
||||
// NameSuffix will suffix the names of all resources mentioned in the kustomization
|
||||
// file including generated configmaps and secrets.
|
||||
NameSuffix string `json:"nameSuffix,omitempty" yaml:"nameSuffix,omitempty"`
|
||||
|
||||
// Namespace to add to all objects.
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
|
||||
// CommonLabels to add to all objects and selectors.
|
||||
CommonLabels map[string]string `json:"commonLabels,omitempty" yaml:"commonLabels,omitempty"`
|
||||
|
||||
// Labels to add to all objects but not selectors.
|
||||
Labels []Label `json:"labels,omitempty" yaml:"labels,omitempty"`
|
||||
|
||||
// CommonAnnotations to add to all objects.
|
||||
CommonAnnotations map[string]string `json:"commonAnnotations,omitempty" yaml:"commonAnnotations,omitempty"`
|
||||
|
||||
// PatchesStrategicMerge specifies the relative path to a file
|
||||
// containing a strategic merge patch. Format documented at
|
||||
// https://github.com/kubernetes/community/blob/master/contributors/devel/strategic-merge-patch.md
|
||||
// URLs and globs are not supported.
|
||||
PatchesStrategicMerge []PatchStrategicMerge `json:"patchesStrategicMerge,omitempty" yaml:"patchesStrategicMerge,omitempty"`
|
||||
|
||||
// JSONPatches is a list of JSONPatch for applying JSON patch.
|
||||
// Format documented at https://tools.ietf.org/html/rfc6902
|
||||
// and http://jsonpatch.com
|
||||
PatchesJson6902 []Patch `json:"patchesJson6902,omitempty" yaml:"patchesJson6902,omitempty"`
|
||||
|
||||
// Patches is a list of patches, where each one can be either a
|
||||
// Strategic Merge Patch or a JSON patch.
|
||||
// Each patch can be applied to multiple target objects.
|
||||
Patches []Patch `json:"patches,omitempty" yaml:"patches,omitempty"`
|
||||
|
||||
// Images is a list of (image name, new name, new tag or digest)
|
||||
// for changing image names, tags or digests. This can also be achieved with a
|
||||
// patch, but this operator is simpler to specify.
|
||||
Images []Image `json:"images,omitempty" yaml:"images,omitempty"`
|
||||
|
||||
// Replicas is a list of {resourcename, count} that allows for simpler replica
|
||||
// specification. This can also be done with a patch.
|
||||
Replicas []Replica `json:"replicas,omitempty" yaml:"replicas,omitempty"`
|
||||
|
||||
// Vars allow things modified by kustomize to be injected into a
|
||||
// kubernetes object specification. A var is a name (e.g. FOO) associated
|
||||
// with a field in a specific resource instance. The field must
|
||||
// contain a value of type string/bool/int/float, and defaults to the name field
|
||||
// of the instance. Any appearance of "$(FOO)" in the object
|
||||
// spec will be replaced at kustomize build time, after the final
|
||||
// value of the specified field has been determined.
|
||||
Vars []Var `json:"vars,omitempty" yaml:"vars,omitempty"`
|
||||
|
||||
//
|
||||
// Operands - what kustomize operates on.
|
||||
//
|
||||
|
||||
// Resources specifies relative paths to files holding YAML representations
|
||||
// of kubernetes API objects, or specifications of other kustomizations
|
||||
// via relative paths, absolute paths, or URLs.
|
||||
Resources []string `json:"resources,omitempty" yaml:"resources,omitempty"`
|
||||
|
||||
// Components specifies relative paths to specifications of other Components
|
||||
// via relative paths, absolute paths, or URLs.
|
||||
Components []string `json:"components,omitempty" yaml:"components,omitempty"`
|
||||
|
||||
// Crds specifies relative paths to Custom Resource Definition files.
|
||||
// This allows custom resources to be recognized as operands, making
|
||||
// it possible to add them to the Resources list.
|
||||
// CRDs themselves are not modified.
|
||||
Crds []string `json:"crds,omitempty" yaml:"crds,omitempty"`
|
||||
|
||||
// Deprecated.
|
||||
// Anything that would have been specified here should
|
||||
// be specified in the Resources field instead.
|
||||
Bases []string `json:"bases,omitempty" yaml:"bases,omitempty"`
|
||||
|
||||
//
|
||||
// Generators (operators that create operands)
|
||||
//
|
||||
|
||||
// ConfigMapGenerator is a list of configmaps to generate from
|
||||
// local data (one configMap per list item).
|
||||
// The resulting resource is a normal operand, subject to
|
||||
// name prefixing, patching, etc. By default, the name of
|
||||
// the map will have a suffix hash generated from its contents.
|
||||
ConfigMapGenerator []ConfigMapArgs `json:"configMapGenerator,omitempty" yaml:"configMapGenerator,omitempty"`
|
||||
|
||||
// SecretGenerator is a list of secrets to generate from
|
||||
// local data (one secret per list item).
|
||||
// The resulting resource is a normal operand, subject to
|
||||
// name prefixing, patching, etc. By default, the name of
|
||||
// the map will have a suffix hash generated from its contents.
|
||||
SecretGenerator []SecretArgs `json:"secretGenerator,omitempty" yaml:"secretGenerator,omitempty"`
|
||||
|
||||
// HelmGlobals contains helm configuration that isn't chart specific.
|
||||
HelmGlobals *HelmGlobals `json:"helmGlobals,omitempty" yaml:"helmGlobals,omitempty"`
|
||||
|
||||
// HelmCharts is a list of helm chart configuration instances.
|
||||
HelmCharts []HelmChart `json:"helmCharts,omitempty" yaml:"helmCharts,omitempty"`
|
||||
|
||||
// HelmChartInflationGenerator is a list of helm chart configurations.
|
||||
// Deprecated. Auto-converted to HelmGlobals and HelmCharts.
|
||||
HelmChartInflationGenerator []HelmChartArgs `json:"helmChartInflationGenerator,omitempty" yaml:"helmChartInflationGenerator,omitempty"`
|
||||
|
||||
// GeneratorOptions modify behavior of all ConfigMap and Secret generators.
|
||||
GeneratorOptions *GeneratorOptions `json:"generatorOptions,omitempty" yaml:"generatorOptions,omitempty"`
|
||||
|
||||
// Configurations is a list of transformer configuration files
|
||||
Configurations []string `json:"configurations,omitempty" yaml:"configurations,omitempty"`
|
||||
|
||||
// Generators is a list of files containing custom generators
|
||||
Generators []string `json:"generators,omitempty" yaml:"generators,omitempty"`
|
||||
|
||||
// Transformers is a list of files containing transformers
|
||||
Transformers []string `json:"transformers,omitempty" yaml:"transformers,omitempty"`
|
||||
|
||||
// Validators is a list of files containing validators
|
||||
Validators []string `json:"validators,omitempty" yaml:"validators,omitempty"`
|
||||
|
||||
// Inventory appends an object that contains the record
|
||||
// of all other objects, which can be used in apply, prune and delete
|
||||
Inventory *Inventory `json:"inventory,omitempty" yaml:"inventory,omitempty"`
|
||||
}
|
||||
|
||||
// FixKustomizationPostUnmarshalling fixes things
|
||||
// like empty fields that should not be empty, or
|
||||
// moving content of deprecated fields to newer
|
||||
// fields.
|
||||
func (k *Kustomization) FixKustomizationPostUnmarshalling() {
|
||||
if k.Kind == "" {
|
||||
k.Kind = KustomizationKind
|
||||
}
|
||||
if k.APIVersion == "" {
|
||||
if k.Kind == ComponentKind {
|
||||
k.APIVersion = ComponentVersion
|
||||
} else {
|
||||
k.APIVersion = KustomizationVersion
|
||||
}
|
||||
}
|
||||
k.Resources = append(k.Resources, k.Bases...)
|
||||
k.Bases = nil
|
||||
for i, g := range k.ConfigMapGenerator {
|
||||
if g.EnvSource != "" {
|
||||
k.ConfigMapGenerator[i].EnvSources =
|
||||
append(g.EnvSources, g.EnvSource)
|
||||
k.ConfigMapGenerator[i].EnvSource = ""
|
||||
}
|
||||
}
|
||||
for i, g := range k.SecretGenerator {
|
||||
if g.EnvSource != "" {
|
||||
k.SecretGenerator[i].EnvSources =
|
||||
append(g.EnvSources, g.EnvSource)
|
||||
k.SecretGenerator[i].EnvSource = ""
|
||||
}
|
||||
}
|
||||
charts, globals := SplitHelmParameters(k.HelmChartInflationGenerator)
|
||||
if k.HelmGlobals == nil {
|
||||
if globals.ChartHome != "" || globals.ConfigHome != "" {
|
||||
k.HelmGlobals = &globals
|
||||
}
|
||||
}
|
||||
k.HelmCharts = append(k.HelmCharts, charts...)
|
||||
// Wipe it for the fix command.
|
||||
k.HelmChartInflationGenerator = nil
|
||||
}
|
||||
|
||||
// FixKustomizationPreMarshalling fixes things
|
||||
// that should occur after the kustomization file
|
||||
// has been processed.
|
||||
func (k *Kustomization) FixKustomizationPreMarshalling() error {
|
||||
// PatchesJson6902 should be under the Patches field.
|
||||
k.Patches = append(k.Patches, k.PatchesJson6902...)
|
||||
k.PatchesJson6902 = nil
|
||||
|
||||
// this fix is not in FixKustomizationPostUnmarshalling because
|
||||
// it will break some commands like `create` and `add`. those
|
||||
// commands depend on 'commonLabels' field
|
||||
if cl := labelFromCommonLabels(k.CommonLabels); cl != nil {
|
||||
// check conflicts between commonLabels and labels
|
||||
for _, l := range k.Labels {
|
||||
for k := range l.Pairs {
|
||||
if _, exist := cl.Pairs[k]; exist {
|
||||
return fmt.Errorf("label name '%s' exists in both commonLabels and labels", k)
|
||||
}
|
||||
}
|
||||
}
|
||||
k.Labels = append(k.Labels, *cl)
|
||||
k.CommonLabels = nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *Kustomization) EnforceFields() []string {
|
||||
var errs []string
|
||||
if k.Kind != "" && k.Kind != KustomizationKind && k.Kind != ComponentKind {
|
||||
errs = append(errs, "kind should be "+KustomizationKind+" or "+ComponentKind)
|
||||
}
|
||||
requiredVersion := KustomizationVersion
|
||||
if k.Kind == ComponentKind {
|
||||
requiredVersion = ComponentVersion
|
||||
}
|
||||
if k.APIVersion != "" && k.APIVersion != requiredVersion {
|
||||
errs = append(errs, "apiVersion for "+k.Kind+" should be "+requiredVersion)
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
// Unmarshal replace k with the content in YAML input y
|
||||
func (k *Kustomization) Unmarshal(y []byte) error {
|
||||
j, err := yaml.YAMLToJSON(y)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dec := json.NewDecoder(bytes.NewReader(j))
|
||||
dec.DisallowUnknownFields()
|
||||
var nk Kustomization
|
||||
err = dec.Decode(&nk)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*k = nk
|
||||
return nil
|
||||
}
|
||||
36
vendor/sigs.k8s.io/kustomize/api/types/kvpairsources.go
generated
vendored
Normal file
36
vendor/sigs.k8s.io/kustomize/api/types/kvpairsources.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// KvPairSources defines places to obtain key value pairs.
|
||||
type KvPairSources struct {
|
||||
// LiteralSources is a list of literal
|
||||
// pair sources. Each literal source should
|
||||
// be a key and literal value, e.g. `key=value`
|
||||
LiteralSources []string `json:"literals,omitempty" yaml:"literals,omitempty"`
|
||||
|
||||
// FileSources is a list of file "sources" to
|
||||
// use in creating a list of key, value pairs.
|
||||
// A source takes the form: [{key}=]{path}
|
||||
// If the "key=" part is missing, the key is the
|
||||
// path's basename. If they "key=" part is present,
|
||||
// it becomes the key (replacing the basename).
|
||||
// In either case, the value is the file contents.
|
||||
// Specifying a directory will iterate each named
|
||||
// file in the directory whose basename is a
|
||||
// valid configmap key.
|
||||
FileSources []string `json:"files,omitempty" yaml:"files,omitempty"`
|
||||
|
||||
// EnvSources is a list of file paths.
|
||||
// The contents of each file should be one
|
||||
// key=value pair per line, e.g. a Docker
|
||||
// or npm ".env" file or a ".ini" file
|
||||
// (wikipedia.org/wiki/INI_file)
|
||||
EnvSources []string `json:"envs,omitempty" yaml:"envs,omitempty"`
|
||||
|
||||
// Older, singular form of EnvSources.
|
||||
// On edits (e.g. `kustomize fix`) this is merged into the plural form
|
||||
// for consistency with LiteralSources and FileSources.
|
||||
EnvSource string `json:"env,omitempty" yaml:"env,omitempty"`
|
||||
}
|
||||
25
vendor/sigs.k8s.io/kustomize/api/types/labels.go
generated
vendored
Normal file
25
vendor/sigs.k8s.io/kustomize/api/types/labels.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
type Label struct {
|
||||
// Pairs contains the key-value pairs for labels to add
|
||||
Pairs map[string]string `json:"pairs,omitempty" yaml:"pairs,omitempty"`
|
||||
// IncludeSelectors inidicates should transformer include the
|
||||
// fieldSpecs for selectors. Custom fieldSpecs specified by
|
||||
// FieldSpecs will be merged with builtin fieldSpecs if this
|
||||
// is true.
|
||||
IncludeSelectors bool `json:"includeSelectors,omitempty" yaml:"includeSelectors,omitempty"`
|
||||
FieldSpecs []FieldSpec `json:"fields,omitempty" yaml:"fields,omitempty"`
|
||||
}
|
||||
|
||||
func labelFromCommonLabels(commonLabels map[string]string) *Label {
|
||||
if len(commonLabels) == 0 {
|
||||
return nil
|
||||
}
|
||||
return &Label{
|
||||
Pairs: commonLabels,
|
||||
IncludeSelectors: true,
|
||||
}
|
||||
}
|
||||
24
vendor/sigs.k8s.io/kustomize/api/types/loadrestrictions.go
generated
vendored
Normal file
24
vendor/sigs.k8s.io/kustomize/api/types/loadrestrictions.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Restrictions on what things can be referred to
|
||||
// in a kustomization file.
|
||||
//
|
||||
//go:generate stringer -type=LoadRestrictions
|
||||
type LoadRestrictions int
|
||||
|
||||
const (
|
||||
LoadRestrictionsUnknown LoadRestrictions = iota
|
||||
|
||||
// Files referenced by a kustomization file must be in
|
||||
// or under the directory holding the kustomization
|
||||
// file itself.
|
||||
LoadRestrictionsRootOnly
|
||||
|
||||
// The kustomization file may specify absolute or
|
||||
// relative paths to patch or resources files outside
|
||||
// its own tree.
|
||||
LoadRestrictionsNone
|
||||
)
|
||||
25
vendor/sigs.k8s.io/kustomize/api/types/loadrestrictions_string.go
generated
vendored
Normal file
25
vendor/sigs.k8s.io/kustomize/api/types/loadrestrictions_string.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// Code generated by "stringer -type=LoadRestrictions"; DO NOT EDIT.
|
||||
|
||||
package types
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[LoadRestrictionsUnknown-0]
|
||||
_ = x[LoadRestrictionsRootOnly-1]
|
||||
_ = x[LoadRestrictionsNone-2]
|
||||
}
|
||||
|
||||
const _LoadRestrictions_name = "LoadRestrictionsUnknownLoadRestrictionsRootOnlyLoadRestrictionsNone"
|
||||
|
||||
var _LoadRestrictions_index = [...]uint8{0, 23, 47, 67}
|
||||
|
||||
func (i LoadRestrictions) String() string {
|
||||
if i < 0 || i >= LoadRestrictions(len(_LoadRestrictions_index)-1) {
|
||||
return "LoadRestrictions(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _LoadRestrictions_name[_LoadRestrictions_index[i]:_LoadRestrictions_index[i+1]]
|
||||
}
|
||||
13
vendor/sigs.k8s.io/kustomize/api/types/objectmeta.go
generated
vendored
Normal file
13
vendor/sigs.k8s.io/kustomize/api/types/objectmeta.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// ObjectMeta partially copies apimachinery/pkg/apis/meta/v1.ObjectMeta
|
||||
// No need for a direct dependence; the fields are stable.
|
||||
type ObjectMeta struct {
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
|
||||
Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
|
||||
}
|
||||
10
vendor/sigs.k8s.io/kustomize/api/types/pair.go
generated
vendored
Normal file
10
vendor/sigs.k8s.io/kustomize/api/types/pair.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Pair is a key value pair.
|
||||
type Pair struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
34
vendor/sigs.k8s.io/kustomize/api/types/patch.go
generated
vendored
Normal file
34
vendor/sigs.k8s.io/kustomize/api/types/patch.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import "reflect"
|
||||
|
||||
// Patch represent either a Strategic Merge Patch or a JSON patch
|
||||
// and its targets.
|
||||
// The content of the patch can either be from a file
|
||||
// or from an inline string.
|
||||
type Patch struct {
|
||||
// Path is a relative file path to the patch file.
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
|
||||
// Patch is the content of a patch.
|
||||
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
|
||||
|
||||
// Target points to the resources that the patch is applied to
|
||||
Target *Selector `json:"target,omitempty" yaml:"target,omitempty"`
|
||||
|
||||
// Options is a list of options for the patch
|
||||
Options map[string]bool `json:"options,omitempty" yaml:"options,omitempty"`
|
||||
}
|
||||
|
||||
// Equals return true if p equals o.
|
||||
func (p *Patch) Equals(o Patch) bool {
|
||||
targetEqual := (p.Target == o.Target) ||
|
||||
(p.Target != nil && o.Target != nil && *p.Target == *o.Target)
|
||||
return p.Path == o.Path &&
|
||||
p.Patch == o.Patch &&
|
||||
targetEqual &&
|
||||
reflect.DeepEqual(p.Options, o.Options)
|
||||
}
|
||||
9
vendor/sigs.k8s.io/kustomize/api/types/patchstrategicmerge.go
generated
vendored
Normal file
9
vendor/sigs.k8s.io/kustomize/api/types/patchstrategicmerge.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// PatchStrategicMerge represents a relative path to a
|
||||
// stategic merge patch with the format
|
||||
// https://github.com/kubernetes/community/blob/master/contributors/devel/sig-api-machinery/strategic-merge-patch.md
|
||||
type PatchStrategicMerge string
|
||||
47
vendor/sigs.k8s.io/kustomize/api/types/pluginconfig.go
generated
vendored
Normal file
47
vendor/sigs.k8s.io/kustomize/api/types/pluginconfig.go
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
type HelmConfig struct {
|
||||
Enabled bool
|
||||
Command string
|
||||
}
|
||||
|
||||
// PluginConfig holds plugin configuration.
|
||||
type PluginConfig struct {
|
||||
// PluginRestrictions distinguishes plugin restrictions.
|
||||
PluginRestrictions PluginRestrictions
|
||||
|
||||
// BpLoadingOptions distinguishes builtin plugin behaviors.
|
||||
BpLoadingOptions BuiltinPluginLoadingOptions
|
||||
|
||||
// FnpLoadingOptions sets the way function-based plugin behaviors.
|
||||
FnpLoadingOptions FnPluginLoadingOptions
|
||||
|
||||
// HelmConfig contains metadata needed for allowing and running helm.
|
||||
HelmConfig HelmConfig
|
||||
}
|
||||
|
||||
func EnabledPluginConfig(b BuiltinPluginLoadingOptions) (pc *PluginConfig) {
|
||||
pc = MakePluginConfig(PluginRestrictionsNone, b)
|
||||
pc.FnpLoadingOptions.EnableStar = true
|
||||
pc.HelmConfig.Enabled = true
|
||||
// If this command is not on PATH, tests needing it should skip.
|
||||
pc.HelmConfig.Command = "helmV3"
|
||||
return
|
||||
}
|
||||
|
||||
func DisabledPluginConfig() *PluginConfig {
|
||||
return MakePluginConfig(
|
||||
PluginRestrictionsBuiltinsOnly,
|
||||
BploUseStaticallyLinked)
|
||||
}
|
||||
|
||||
func MakePluginConfig(pr PluginRestrictions,
|
||||
b BuiltinPluginLoadingOptions) *PluginConfig {
|
||||
return &PluginConfig{
|
||||
PluginRestrictions: pr,
|
||||
BpLoadingOptions: b,
|
||||
}
|
||||
}
|
||||
58
vendor/sigs.k8s.io/kustomize/api/types/pluginrestrictions.go
generated
vendored
Normal file
58
vendor/sigs.k8s.io/kustomize/api/types/pluginrestrictions.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Some plugin classes
|
||||
// - builtin: plugins defined in the kustomize repo.
|
||||
// May be freely used and re-configured.
|
||||
// - local: plugins that aren't builtin but are
|
||||
// locally defined (presumably by the user), meaning
|
||||
// the kustomization refers to them via a relative
|
||||
// file path, not a URL.
|
||||
// - remote: require a build-time download to obtain.
|
||||
// Unadvised, unless one controls the
|
||||
// serving site.
|
||||
//
|
||||
//go:generate stringer -type=PluginRestrictions
|
||||
type PluginRestrictions int
|
||||
|
||||
const (
|
||||
PluginRestrictionsUnknown PluginRestrictions = iota
|
||||
|
||||
// Non-builtin plugins completely disabled.
|
||||
PluginRestrictionsBuiltinsOnly
|
||||
|
||||
// No restrictions, do whatever you want.
|
||||
PluginRestrictionsNone
|
||||
)
|
||||
|
||||
// BuiltinPluginLoadingOptions distinguish ways in which builtin plugins are used.
|
||||
//go:generate stringer -type=BuiltinPluginLoadingOptions
|
||||
type BuiltinPluginLoadingOptions int
|
||||
|
||||
const (
|
||||
BploUndefined BuiltinPluginLoadingOptions = iota
|
||||
|
||||
// Desired in production use for performance.
|
||||
BploUseStaticallyLinked
|
||||
|
||||
// Desired in testing and development cycles where it's undesirable
|
||||
// to generate static code.
|
||||
BploLoadFromFileSys
|
||||
)
|
||||
|
||||
// FnPluginLoadingOptions set way functions-based pluing are restricted
|
||||
type FnPluginLoadingOptions struct {
|
||||
// Allow to run executables
|
||||
EnableExec bool
|
||||
// Allow to run starlark
|
||||
EnableStar bool
|
||||
// Allow container access to network
|
||||
Network bool
|
||||
NetworkName string
|
||||
// list of mounts
|
||||
Mounts []string
|
||||
// list of env variables to pass to fn
|
||||
Env []string
|
||||
}
|
||||
25
vendor/sigs.k8s.io/kustomize/api/types/pluginrestrictions_string.go
generated
vendored
Normal file
25
vendor/sigs.k8s.io/kustomize/api/types/pluginrestrictions_string.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// Code generated by "stringer -type=PluginRestrictions"; DO NOT EDIT.
|
||||
|
||||
package types
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[PluginRestrictionsUnknown-0]
|
||||
_ = x[PluginRestrictionsBuiltinsOnly-1]
|
||||
_ = x[PluginRestrictionsNone-2]
|
||||
}
|
||||
|
||||
const _PluginRestrictions_name = "PluginRestrictionsUnknownPluginRestrictionsBuiltinsOnlyPluginRestrictionsNone"
|
||||
|
||||
var _PluginRestrictions_index = [...]uint8{0, 25, 55, 77}
|
||||
|
||||
func (i PluginRestrictions) String() string {
|
||||
if i < 0 || i >= PluginRestrictions(len(_PluginRestrictions_index)-1) {
|
||||
return "PluginRestrictions(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _PluginRestrictions_name[_PluginRestrictions_index[i]:_PluginRestrictions_index[i+1]]
|
||||
}
|
||||
59
vendor/sigs.k8s.io/kustomize/api/types/replacement.go
generated
vendored
Normal file
59
vendor/sigs.k8s.io/kustomize/api/types/replacement.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright 2021 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
const DefaultReplacementFieldPath = "metadata.name"
|
||||
|
||||
// Replacement defines how to perform a substitution
|
||||
// where it is from and where it is to.
|
||||
type Replacement struct {
|
||||
// The source of the value.
|
||||
Source *SourceSelector `json:"source" yaml:"source"`
|
||||
|
||||
// The N fields to write the value to.
|
||||
Targets []*TargetSelector `json:"targets" yaml:"targets"`
|
||||
}
|
||||
|
||||
// SourceSelector is the source of the replacement transformer.
|
||||
type SourceSelector struct {
|
||||
// A specific object to read it from.
|
||||
KrmId `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
|
||||
// Structured field path expected in the allowed object.
|
||||
FieldPath string `json:"fieldPath" yaml:"fieldPath"`
|
||||
|
||||
// Used to refine the interpretation of the field.
|
||||
Options *FieldOptions `json:"options" yaml:"options"`
|
||||
}
|
||||
|
||||
// TargetSelector specifies fields in one or more objects.
|
||||
type TargetSelector struct {
|
||||
// Include objects that match this.
|
||||
Select *Selector `json:"select" yaml:"select"`
|
||||
|
||||
// From the allowed set, remove objects that match this.
|
||||
Reject []*Selector `json:"reject" yaml:"reject"`
|
||||
|
||||
// Structured field paths expected in each allowed object.
|
||||
FieldPaths []string `json:"fieldPaths" yaml:"fieldPaths"`
|
||||
|
||||
// Used to refine the interpretation of the field.
|
||||
Options *FieldOptions `json:"options" yaml:"options"`
|
||||
}
|
||||
|
||||
// FieldOptions refine the interpretation of FieldPaths.
|
||||
type FieldOptions struct {
|
||||
// Used to split/join the field.
|
||||
Delimiter string `json:"delimiter" yaml:"delimiter"`
|
||||
|
||||
// Which position in the split to consider.
|
||||
Index int `json:"index" yaml:"index"`
|
||||
|
||||
// TODO (#3492): Implement use of this option
|
||||
// None, Base64, URL, Hex, etc
|
||||
Encoding string `json:"encoding" yaml:"encoding"`
|
||||
|
||||
// If field missing, add it.
|
||||
Create bool `json:"create" yaml:"create"`
|
||||
}
|
||||
16
vendor/sigs.k8s.io/kustomize/api/types/replica.go
generated
vendored
Normal file
16
vendor/sigs.k8s.io/kustomize/api/types/replica.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Replica specifies a modification to a replica config.
|
||||
// The number of replicas of a resource whose name matches will be set to count.
|
||||
// This struct is used by the ReplicaCountTransform, and is meant to supplement
|
||||
// the existing patch functionality with a simpler syntax for replica configuration.
|
||||
type Replica struct {
|
||||
// The name of the resource to change the replica count
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
|
||||
// The number of replicas required.
|
||||
Count int64 `json:"count" yaml:"count"`
|
||||
}
|
||||
19
vendor/sigs.k8s.io/kustomize/api/types/secretargs.go
generated
vendored
Normal file
19
vendor/sigs.k8s.io/kustomize/api/types/secretargs.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// SecretArgs contains the metadata of how to generate a secret.
|
||||
type SecretArgs struct {
|
||||
// GeneratorArgs for the secret.
|
||||
GeneratorArgs `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
|
||||
// Type of the secret.
|
||||
//
|
||||
// This is the same field as the secret type field in v1/Secret:
|
||||
// It can be "Opaque" (default), or "kubernetes.io/tls".
|
||||
//
|
||||
// If type is "kubernetes.io/tls", then "literals" or "files" must have exactly two
|
||||
// keys: "tls.key" and "tls.crt"
|
||||
Type string `json:"type,omitempty" yaml:"type,omitempty"`
|
||||
}
|
||||
131
vendor/sigs.k8s.io/kustomize/api/types/selector.go
generated
vendored
Normal file
131
vendor/sigs.k8s.io/kustomize/api/types/selector.go
generated
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
)
|
||||
|
||||
// Selector specifies a set of resources.
|
||||
// Any resource that matches intersection of all conditions
|
||||
// is included in this set.
|
||||
type Selector struct {
|
||||
// KrmId refers to a GVKN/Ns of a resource.
|
||||
KrmId `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
|
||||
// AnnotationSelector is a string that follows the label selection expression
|
||||
// https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
|
||||
// It matches with the resource annotations.
|
||||
AnnotationSelector string `json:"annotationSelector,omitempty" yaml:"annotationSelector,omitempty"`
|
||||
|
||||
// LabelSelector is a string that follows the label selection expression
|
||||
// https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
|
||||
// It matches with the resource labels.
|
||||
LabelSelector string `json:"labelSelector,omitempty" yaml:"labelSelector,omitempty"`
|
||||
}
|
||||
|
||||
// KrmId refers to a GVKN/Ns of a resource.
|
||||
type KrmId struct {
|
||||
resid.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
// Match returns true if id selects other, i.e. id's fields
|
||||
// either match other's or are empty
|
||||
func (id *KrmId) Match(other *KrmId) bool {
|
||||
return (id.Group == "" || id.Group == other.Group) &&
|
||||
(id.Version == "" || id.Version == other.Version) &&
|
||||
(id.Kind == "" || id.Kind == other.Kind) &&
|
||||
(id.Name == "" || id.Name == other.Name) &&
|
||||
(id.Namespace == "" || id.Namespace == other.Namespace)
|
||||
}
|
||||
|
||||
// SelectorRegex is a Selector with regex in GVK
|
||||
// Any resource that matches intersection of all conditions
|
||||
// is included in this set.
|
||||
type SelectorRegex struct {
|
||||
selector *Selector
|
||||
groupRegex *regexp.Regexp
|
||||
versionRegex *regexp.Regexp
|
||||
kindRegex *regexp.Regexp
|
||||
nameRegex *regexp.Regexp
|
||||
namespaceRegex *regexp.Regexp
|
||||
}
|
||||
|
||||
// NewSelectorRegex returns a pointer to a new SelectorRegex
|
||||
// which uses the same condition as s.
|
||||
func NewSelectorRegex(s *Selector) (*SelectorRegex, error) {
|
||||
sr := new(SelectorRegex)
|
||||
var err error
|
||||
sr.selector = s
|
||||
sr.groupRegex, err = regexp.Compile(anchorRegex(s.Gvk.Group))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sr.versionRegex, err = regexp.Compile(anchorRegex(s.Gvk.Version))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sr.kindRegex, err = regexp.Compile(anchorRegex(s.Gvk.Kind))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sr.nameRegex, err = regexp.Compile(anchorRegex(s.Name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sr.namespaceRegex, err = regexp.Compile(anchorRegex(s.Namespace))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sr, nil
|
||||
}
|
||||
|
||||
func anchorRegex(pattern string) string {
|
||||
if pattern == "" {
|
||||
return pattern
|
||||
}
|
||||
return "^(?:" + pattern + ")$"
|
||||
}
|
||||
|
||||
// MatchGvk return true if gvk can be matched by s.
|
||||
func (s *SelectorRegex) MatchGvk(gvk resid.Gvk) bool {
|
||||
if len(s.selector.Gvk.Group) > 0 {
|
||||
if !s.groupRegex.MatchString(gvk.Group) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if len(s.selector.Gvk.Version) > 0 {
|
||||
if !s.versionRegex.MatchString(gvk.Version) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if len(s.selector.Gvk.Kind) > 0 {
|
||||
if !s.kindRegex.MatchString(gvk.Kind) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// MatchName returns true if the name in selector is
|
||||
// empty or the n can be matches by the name in selector
|
||||
func (s *SelectorRegex) MatchName(n string) bool {
|
||||
if s.selector.Name == "" {
|
||||
return true
|
||||
}
|
||||
return s.nameRegex.MatchString(n)
|
||||
}
|
||||
|
||||
// MatchNamespace returns true if the namespace in selector is
|
||||
// empty or the ns can be matches by the namespace in selector
|
||||
func (s *SelectorRegex) MatchNamespace(ns string) bool {
|
||||
if s.selector.Namespace == "" {
|
||||
return true
|
||||
}
|
||||
return s.namespaceRegex.MatchString(ns)
|
||||
}
|
||||
11
vendor/sigs.k8s.io/kustomize/api/types/typemeta.go
generated
vendored
Normal file
11
vendor/sigs.k8s.io/kustomize/api/types/typemeta.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// TypeMeta partially copies apimachinery/pkg/apis/meta/v1.TypeMeta
|
||||
// No need for a direct dependence; the fields are stable.
|
||||
type TypeMeta struct {
|
||||
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
|
||||
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
|
||||
}
|
||||
211
vendor/sigs.k8s.io/kustomize/api/types/var.go
generated
vendored
Normal file
211
vendor/sigs.k8s.io/kustomize/api/types/var.go
generated
vendored
Normal file
@@ -0,0 +1,211 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
)
|
||||
|
||||
// Var represents a variable whose value will be sourced
|
||||
// from a field in a Kubernetes object.
|
||||
type Var struct {
|
||||
// Value of identifier name e.g. FOO used in container args, annotations
|
||||
// Appears in pod template as $(FOO)
|
||||
Name string `json:"name" yaml:"name"`
|
||||
|
||||
// ObjRef must refer to a Kubernetes resource under the
|
||||
// purview of this kustomization. ObjRef should use the
|
||||
// raw name of the object (the name specified in its YAML,
|
||||
// before addition of a namePrefix and a nameSuffix).
|
||||
ObjRef Target `json:"objref" yaml:"objref"`
|
||||
|
||||
// FieldRef refers to the field of the object referred to by
|
||||
// ObjRef whose value will be extracted for use in
|
||||
// replacing $(FOO).
|
||||
// If unspecified, this defaults to fieldPath: $defaultFieldPath
|
||||
FieldRef FieldSelector `json:"fieldref,omitempty" yaml:"fieldref,omitempty"`
|
||||
}
|
||||
|
||||
// Target refers to a kubernetes object by Group, Version, Kind and Name
|
||||
// gvk.Gvk contains Group, Version and Kind
|
||||
// APIVersion is added to keep the backward compatibility of using ObjectReference
|
||||
// for Var.ObjRef
|
||||
type Target struct {
|
||||
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
|
||||
resid.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
Name string `json:"name" yaml:"name"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
// GVK returns the Gvk object in Target
|
||||
func (t *Target) GVK() resid.Gvk {
|
||||
if t.APIVersion == "" {
|
||||
return t.Gvk
|
||||
}
|
||||
versions := strings.Split(t.APIVersion, "/")
|
||||
if len(versions) == 2 {
|
||||
t.Group = versions[0]
|
||||
t.Version = versions[1]
|
||||
}
|
||||
if len(versions) == 1 {
|
||||
t.Version = versions[0]
|
||||
}
|
||||
return t.Gvk
|
||||
}
|
||||
|
||||
// FieldSelector contains the fieldPath to an object field.
|
||||
// This struct is added to keep the backward compatibility of using ObjectFieldSelector
|
||||
// for Var.FieldRef
|
||||
type FieldSelector struct {
|
||||
FieldPath string `json:"fieldPath,omitempty" yaml:"fieldPath,omitempty"`
|
||||
}
|
||||
|
||||
// defaulting sets reference to field used by default.
|
||||
func (v *Var) Defaulting() {
|
||||
if v.FieldRef.FieldPath == "" {
|
||||
v.FieldRef.FieldPath = DefaultReplacementFieldPath
|
||||
}
|
||||
v.ObjRef.GVK()
|
||||
}
|
||||
|
||||
// DeepEqual returns true if var a and b are Equals.
|
||||
// Note 1: The objects are unchanged by the VarEqual
|
||||
// Note 2: Should be normalize be FieldPath before doing
|
||||
// the DeepEqual. spec.a[b] is supposed to be the same
|
||||
// as spec.a.b
|
||||
func (v Var) DeepEqual(other Var) bool {
|
||||
v.Defaulting()
|
||||
other.Defaulting()
|
||||
return reflect.DeepEqual(v, other)
|
||||
}
|
||||
|
||||
// VarSet is a set of Vars where no var.Name is repeated.
|
||||
type VarSet struct {
|
||||
set map[string]Var
|
||||
}
|
||||
|
||||
// NewVarSet returns an initialized VarSet
|
||||
func NewVarSet() VarSet {
|
||||
return VarSet{set: map[string]Var{}}
|
||||
}
|
||||
|
||||
// AsSlice returns the vars as a slice.
|
||||
func (vs *VarSet) AsSlice() []Var {
|
||||
s := make([]Var, len(vs.set))
|
||||
i := 0
|
||||
for _, v := range vs.set {
|
||||
s[i] = v
|
||||
i++
|
||||
}
|
||||
sort.Sort(byName(s))
|
||||
return s
|
||||
}
|
||||
|
||||
// Copy returns a copy of the var set.
|
||||
func (vs *VarSet) Copy() VarSet {
|
||||
newSet := make(map[string]Var, len(vs.set))
|
||||
for k, v := range vs.set {
|
||||
newSet[k] = v
|
||||
}
|
||||
return VarSet{set: newSet}
|
||||
}
|
||||
|
||||
// MergeSet absorbs other vars with error on name collision.
|
||||
func (vs *VarSet) MergeSet(incoming VarSet) error {
|
||||
for _, incomingVar := range incoming.set {
|
||||
if err := vs.Merge(incomingVar); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MergeSlice absorbs a Var slice with error on name collision.
|
||||
// Empty fields in incoming vars are defaulted.
|
||||
func (vs *VarSet) MergeSlice(incoming []Var) error {
|
||||
for _, v := range incoming {
|
||||
if err := vs.Merge(v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Merge absorbs another Var with error on name collision.
|
||||
// Empty fields in incoming Var is defaulted.
|
||||
func (vs *VarSet) Merge(v Var) error {
|
||||
if vs.Contains(v) {
|
||||
return fmt.Errorf(
|
||||
"var '%s' already encountered", v.Name)
|
||||
}
|
||||
v.Defaulting()
|
||||
vs.set[v.Name] = v
|
||||
return nil
|
||||
}
|
||||
|
||||
// AbsorbSet absorbs other vars with error on (name,value) collision.
|
||||
func (vs *VarSet) AbsorbSet(incoming VarSet) error {
|
||||
for _, v := range incoming.set {
|
||||
if err := vs.Absorb(v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AbsorbSlice absorbs a Var slice with error on (name,value) collision.
|
||||
// Empty fields in incoming vars are defaulted.
|
||||
func (vs *VarSet) AbsorbSlice(incoming []Var) error {
|
||||
for _, v := range incoming {
|
||||
if err := vs.Absorb(v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Absorb absorbs another Var with error on (name,value) collision.
|
||||
// Empty fields in incoming Var is defaulted.
|
||||
func (vs *VarSet) Absorb(v Var) error {
|
||||
conflicting := vs.Get(v.Name)
|
||||
if conflicting == nil {
|
||||
// no conflict. The var is valid.
|
||||
v.Defaulting()
|
||||
vs.set[v.Name] = v
|
||||
return nil
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(v, *conflicting) {
|
||||
// two vars with the same name are pointing at two
|
||||
// different resources.
|
||||
return fmt.Errorf(
|
||||
"var '%s' already encountered", v.Name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Contains is true if the set has the other var.
|
||||
func (vs *VarSet) Contains(other Var) bool {
|
||||
return vs.Get(other.Name) != nil
|
||||
}
|
||||
|
||||
// Get returns the var with the given name, else nil.
|
||||
func (vs *VarSet) Get(name string) *Var {
|
||||
if v, found := vs.set[name]; found {
|
||||
return &v
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// byName is a sort interface which sorts Vars by name alphabetically
|
||||
type byName []Var
|
||||
|
||||
func (v byName) Len() int { return len(v) }
|
||||
func (v byName) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
|
||||
func (v byName) Less(i, j int) bool { return v[i].Name < v[j].Name }
|
||||
201
vendor/sigs.k8s.io/kustomize/kyaml/LICENSE
generated
vendored
Normal file
201
vendor/sigs.k8s.io/kustomize/kyaml/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
2
vendor/sigs.k8s.io/kustomize/kyaml/LICENSE_TEMPLATE
generated
vendored
Normal file
2
vendor/sigs.k8s.io/kustomize/kyaml/LICENSE_TEMPLATE
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
Copyright {{.Year}} {{.Holder}}
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
40
vendor/sigs.k8s.io/kustomize/kyaml/errors/errors.go
generated
vendored
Normal file
40
vendor/sigs.k8s.io/kustomize/kyaml/errors/errors.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package errors provides libraries for working with the go-errors/errors library.
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
goerrors "github.com/go-errors/errors"
|
||||
)
|
||||
|
||||
// Wrap returns err wrapped in a go-error. If err is nil, returns nil.
|
||||
func Wrap(err interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return goerrors.Wrap(err, 1)
|
||||
}
|
||||
|
||||
// WrapPrefixf returns err wrapped in a go-error with a message prefix. If err is nil, returns nil.
|
||||
func WrapPrefixf(err interface{}, msg string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return goerrors.WrapPrefix(err, fmt.Sprintf(msg, args...), 1)
|
||||
}
|
||||
|
||||
// Errorf returns a new go-error.
|
||||
func Errorf(msg string, args ...interface{}) error {
|
||||
return goerrors.Wrap(fmt.Errorf(msg, args...), 1)
|
||||
}
|
||||
|
||||
// GetStack returns a stack trace for the error if it has one
|
||||
func GetStack(err error) string {
|
||||
if e, ok := err.(*goerrors.Error); ok {
|
||||
return string(e.Stack())
|
||||
}
|
||||
return ""
|
||||
}
|
||||
61
vendor/sigs.k8s.io/kustomize/kyaml/openapi/Makefile
generated
vendored
Normal file
61
vendor/sigs.k8s.io/kustomize/kyaml/openapi/Makefile
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
# Copyright 2020 The Kubernetes Authors.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
MYGOBIN = $(shell go env GOBIN)
|
||||
ifeq ($(MYGOBIN),)
|
||||
MYGOBIN = $(shell go env GOPATH)/bin
|
||||
endif
|
||||
API_VERSION := "v1.19.1"
|
||||
|
||||
.PHONY: all
|
||||
all: \
|
||||
kustomizationapi/swagger.go \
|
||||
kubernetesapi/swagger.go \
|
||||
kubernetesapi/openapiinfo.go
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm kustomizationapi/swagger.go
|
||||
rm kubernetesapi/openapiinfo.go
|
||||
|
||||
# This will remove all currently built-in schema,
|
||||
# so think twice before deleting.
|
||||
# To replace what this will delete typically requires the ability
|
||||
# to contact a live kubernetes API server.
|
||||
.PHONY: nuke
|
||||
nuke: clean
|
||||
rm -r kubernetesapi/*
|
||||
|
||||
$(MYGOBIN)/go-bindata:
|
||||
go install github.com/go-bindata/go-bindata/v3/go-bindata
|
||||
|
||||
$(MYGOBIN)/kind:
|
||||
( \
|
||||
set -e; \
|
||||
d=$(shell mktemp -d); cd $$d; \
|
||||
wget -O ./kind https://github.com/kubernetes-sigs/kind/releases/download/v0.7.0/kind-$(shell uname)-amd64; \
|
||||
chmod +x ./kind; \
|
||||
mv ./kind $(MYGOBIN); \
|
||||
rm -rf $$d; \
|
||||
)
|
||||
|
||||
$(MYGOBIN)/kpt:
|
||||
../../hack/install_kpt.sh 0.34.0 $(MYGOBIN)
|
||||
|
||||
kustomizationapi/swagger.go: $(MYGOBIN)/go-bindata kustomizationapi/swagger.json
|
||||
$(MYGOBIN)/go-bindata \
|
||||
--pkg kustomizationapi \
|
||||
-o kustomizationapi/swagger.go \
|
||||
kustomizationapi/swagger.json
|
||||
|
||||
.PHONY: kubernetesapi/openapiinfo.go
|
||||
kubernetesapi/openapiinfo.go:
|
||||
./scripts/makeOpenApiInfoDotGo.sh
|
||||
|
||||
.PHONY: kubernetesapi/swagger.json
|
||||
kubernetesapi/swagger.json: $(MYGOBIN)/kind $(MYGOBIN)/kpt
|
||||
./scripts/fetchSchemaFromCluster.sh $(API_VERSION)
|
||||
|
||||
.PHONY: kubernetesapi/swagger.go
|
||||
kubernetesapi/swagger.go: $(MYGOBIN)/go-bindata kubernetesapi/swagger.json
|
||||
./scripts/generateSwaggerDotGo.sh $(API_VERSION)
|
||||
63
vendor/sigs.k8s.io/kustomize/kyaml/openapi/README.md
generated
vendored
Normal file
63
vendor/sigs.k8s.io/kustomize/kyaml/openapi/README.md
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
# Sampling New OpenAPI Data
|
||||
|
||||
[OpenAPI schema]: ./kubernetesapi/
|
||||
[kind]: https://hub.docker.com/r/kindest/node/tags
|
||||
|
||||
This document describes how to fetch OpenAPI data from a
|
||||
live kubernetes API server, e.g. an instance of [kind].
|
||||
|
||||
### Delete all currently built-in schema
|
||||
```
|
||||
make nuke
|
||||
```
|
||||
|
||||
### Add a new built-in schema
|
||||
|
||||
In this directory, fetch the openapi schema and generate the
|
||||
corresponding swagger.go for the kubernetes api:
|
||||
|
||||
```
|
||||
make kubernetesapi/swagger.go
|
||||
```
|
||||
|
||||
To fetch the schema without generating the swagger.go, you can
|
||||
run:
|
||||
|
||||
```
|
||||
make nuke
|
||||
make kubernetesapi/swagger.json
|
||||
```
|
||||
|
||||
Note that generating the swagger.go will re-fetch the schema.
|
||||
|
||||
You can specify a specific version with the "API_VERSION"
|
||||
parameter. The default version is v1.19.1. Here is an
|
||||
example for generating swagger.go for v1.14.1.
|
||||
|
||||
```
|
||||
make kubernetesapi/swagger.go API_VERSION=v1.14.1
|
||||
```
|
||||
|
||||
This will update the [OpenAPI schema]. The above command will
|
||||
create a directory kubernetesapi/v1141 and store the resulting
|
||||
swagger.json and swagger.go files there.
|
||||
|
||||
### Make the schema available for use
|
||||
|
||||
While the above commands generate the swagger.go files, they
|
||||
do not make them available for use nor do they update the
|
||||
info field reported by `kustomize openapi info`. To make the
|
||||
newly fetched schema and swagger.go available:
|
||||
|
||||
```
|
||||
make kubernetesapi/openapiinfo.go
|
||||
```
|
||||
|
||||
### Run all tests
|
||||
|
||||
At the top of the repository, run the tests.
|
||||
|
||||
```
|
||||
make prow-presubmit-check >& /tmp/k.txt; echo $?
|
||||
# The exit code should be zero; if not examine /tmp/k.txt
|
||||
```
|
||||
18
vendor/sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi/openapiinfo.go
generated
vendored
Normal file
18
vendor/sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi/openapiinfo.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by ./scripts/makeOpenApiInfoDotGo.sh; DO NOT EDIT.
|
||||
|
||||
package kubernetesapi
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi/v1204"
|
||||
)
|
||||
|
||||
const Info = "{title:Kubernetes,version:v1.20.4}"
|
||||
|
||||
var OpenAPIMustAsset = map[string]func(string) []byte{
|
||||
"v1204": v1204.MustAsset,
|
||||
}
|
||||
|
||||
const DefaultOpenAPI = "v1204"
|
||||
251
vendor/sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi/v1204/swagger.go
generated
vendored
Normal file
251
vendor/sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi/v1204/swagger.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
96625
vendor/sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi/v1204/swagger.json
generated
vendored
Normal file
96625
vendor/sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi/v1204/swagger.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
249
vendor/sigs.k8s.io/kustomize/kyaml/openapi/kustomizationapi/swagger.go
generated
vendored
Normal file
249
vendor/sigs.k8s.io/kustomize/kyaml/openapi/kustomizationapi/swagger.go
generated
vendored
Normal file
@@ -0,0 +1,249 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated for package kustomizationapi by go-bindata DO NOT EDIT. (@generated)
|
||||
// sources:
|
||||
// kustomizationapi/swagger.json
|
||||
package kustomizationapi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func bindataRead(data []byte, name string) ([]byte, error) {
|
||||
gz, err := gzip.NewReader(bytes.NewBuffer(data))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Read %q: %v", name, err)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
_, err = io.Copy(&buf, gz)
|
||||
clErr := gz.Close()
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Read %q: %v", name, err)
|
||||
}
|
||||
if clErr != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
type asset struct {
|
||||
bytes []byte
|
||||
info os.FileInfo
|
||||
}
|
||||
|
||||
type bindataFileInfo struct {
|
||||
name string
|
||||
size int64
|
||||
mode os.FileMode
|
||||
modTime time.Time
|
||||
}
|
||||
|
||||
// Name return file name
|
||||
func (fi bindataFileInfo) Name() string {
|
||||
return fi.name
|
||||
}
|
||||
|
||||
// Size return file size
|
||||
func (fi bindataFileInfo) Size() int64 {
|
||||
return fi.size
|
||||
}
|
||||
|
||||
// Mode return file mode
|
||||
func (fi bindataFileInfo) Mode() os.FileMode {
|
||||
return fi.mode
|
||||
}
|
||||
|
||||
// Mode return file modify time
|
||||
func (fi bindataFileInfo) ModTime() time.Time {
|
||||
return fi.modTime
|
||||
}
|
||||
|
||||
// IsDir return file whether a directory
|
||||
func (fi bindataFileInfo) IsDir() bool {
|
||||
return fi.mode&os.ModeDir != 0
|
||||
}
|
||||
|
||||
// Sys return file is sys mode
|
||||
func (fi bindataFileInfo) Sys() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
var _kustomizationapiSwaggerJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xe4\x56\xc1\x6e\xdb\x30\x0c\xbd\xe7\x2b\x04\x6d\xc7\xd8\x45\x6e\x43\x6e\xc3\x0e\x3b\x14\x05\x0a\x74\xb7\xa1\x07\xc6\xa1\x5d\xce\x8e\xa4\x51\xb4\xb1\x6c\xc8\xbf\x0f\xd6\x62\xd7\x4a\xec\x75\x0b\x1a\xac\x4b\x0f\x06\x0c\x99\x7c\x4f\xe4\x7b\x24\xfc\x63\xa6\x94\x5e\x63\x4e\x86\x84\xac\xf1\x7a\xa9\xda\x23\xa5\x34\xd9\xb4\x7c\xe7\x53\x70\x94\x82\x73\x3e\x6d\x16\xe9\x07\x6b\x72\x2a\x6e\xc0\xbd\xe7\xe2\x31\x52\x29\xed\xd8\x3a\x64\x21\x1c\x9e\x2a\xa5\x3f\xa2\x41\x06\xb1\x7c\x90\x10\x3e\xbe\x65\xcc\xf5\x52\xe9\x37\x57\x03\xfe\xab\x11\xda\x18\xa5\x87\xd8\xed\xdf\x76\xf3\xee\x1a\xb0\x5e\x07\x14\xa8\x6e\x87\x17\xca\xa1\xf2\xd8\x07\xc9\xd6\x61\x4b\x6b\x57\x5f\x30\x13\xdd\x9f\x7f\x4b\xca\x7a\x85\x6c\x50\xd0\x27\x05\xdb\xda\x25\x0d\xb2\x27\x6b\x92\x92\xcc\x5a\x2f\xd5\xe7\x9e\x3a\xaa\x23\xc4\xb6\x88\x65\xed\xc5\x6e\xe8\x3b\xa6\x59\x68\x54\x28\x84\x6c\x4f\x11\xa2\xf7\x58\x3a\xee\x65\x14\xb2\xa7\x6d\xa3\x9a\xc5\x0a\x05\x16\xc7\x45\xdf\xcf\x06\xa5\x8f\x69\x75\x87\x19\xa3\xbc\x0c\xa1\x1e\xab\xeb\xba\x1f\xe1\x77\x8a\x78\x61\x32\xc5\xa5\x08\x3c\x10\xe0\xf9\xd5\x9d\xd2\x6b\x52\x60\x03\x1b\xf4\x0e\xb2\x3f\x6f\xfe\x3c\x4e\x3e\x25\x6f\x85\x0f\xd0\x90\xe5\x53\x72\xaf\x9b\x5b\x20\xbe\xb3\x35\x67\x78\xba\x23\x63\x94\x0b\x71\x56\x2c\xfe\xf3\x9b\xeb\x7a\x7f\x19\x90\x5f\x50\xbd\xb9\x18\xbf\xd6\xc4\x18\x17\xa4\x3f\x6d\x1d\xde\xa0\x40\xc7\x74\x3f\x7f\xca\x8c\x59\xb7\xfb\xfa\x4a\x0e\x05\x26\xc1\xcd\xa1\xea\x7f\xa3\x7b\xbc\x5d\x07\x20\xbb\xf9\x98\x11\x81\x19\xb6\x71\x27\x23\x4d\x1d\x48\xf6\x90\x6c\x90\x0b\x4c\x4a\xdc\xb6\x29\x61\x26\x9e\xca\xf0\xc2\x20\x58\x84\x84\x90\x3d\xee\x75\x1f\x56\xc5\xd9\x9a\x31\xd8\x44\x2f\xb2\x13\xff\xf5\x30\xc6\xc3\x72\x86\x61\x9c\xd8\x83\x93\xc3\x55\x91\x20\x43\x75\xb4\x33\x27\x5c\x34\xb5\x8b\x7f\x6f\x90\x51\x1b\xe7\x54\x1d\xaf\xea\xf3\xd3\xa2\x69\xfe\x0d\xeb\xeb\xf8\x8f\x89\x0d\x78\xaa\xc1\x67\xed\xb3\xfb\x19\x00\x00\xff\xff\x2f\x39\x79\xd0\x6e\x0c\x00\x00")
|
||||
|
||||
func kustomizationapiSwaggerJsonBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
_kustomizationapiSwaggerJson,
|
||||
"kustomizationapi/swagger.json",
|
||||
)
|
||||
}
|
||||
|
||||
func kustomizationapiSwaggerJson() (*asset, error) {
|
||||
bytes, err := kustomizationapiSwaggerJsonBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "kustomizationapi/swagger.json", size: 3182, mode: os.FileMode(420), modTime: time.Unix(1615228558, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// Asset loads and returns the asset for the given name.
|
||||
// It returns an error if the asset could not be found or
|
||||
// could not be loaded.
|
||||
func Asset(name string) ([]byte, error) {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
if f, ok := _bindata[cannonicalName]; ok {
|
||||
a, err := f()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
|
||||
}
|
||||
return a.bytes, nil
|
||||
}
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
|
||||
// MustAsset is like Asset but panics when Asset would return an error.
|
||||
// It simplifies safe initialization of global variables.
|
||||
func MustAsset(name string) []byte {
|
||||
a, err := Asset(name)
|
||||
if err != nil {
|
||||
panic("asset: Asset(" + name + "): " + err.Error())
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// AssetInfo loads and returns the asset info for the given name.
|
||||
// It returns an error if the asset could not be found or
|
||||
// could not be loaded.
|
||||
func AssetInfo(name string) (os.FileInfo, error) {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
if f, ok := _bindata[cannonicalName]; ok {
|
||||
a, err := f()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
|
||||
}
|
||||
return a.info, nil
|
||||
}
|
||||
return nil, fmt.Errorf("AssetInfo %s not found", name)
|
||||
}
|
||||
|
||||
// AssetNames returns the names of the assets.
|
||||
func AssetNames() []string {
|
||||
names := make([]string, 0, len(_bindata))
|
||||
for name := range _bindata {
|
||||
names = append(names, name)
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
// _bindata is a table, holding each asset generator, mapped to its name.
|
||||
var _bindata = map[string]func() (*asset, error){
|
||||
"kustomizationapi/swagger.json": kustomizationapiSwaggerJson,
|
||||
}
|
||||
|
||||
// AssetDir returns the file names below a certain
|
||||
// directory embedded in the file by go-bindata.
|
||||
// For example if you run go-bindata on data/... and data contains the
|
||||
// following hierarchy:
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||
// AssetDir("") will return []string{"data"}.
|
||||
func AssetDir(name string) ([]string, error) {
|
||||
node := _bintree
|
||||
if len(name) != 0 {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
pathList := strings.Split(cannonicalName, "/")
|
||||
for _, p := range pathList {
|
||||
node = node.Children[p]
|
||||
if node == nil {
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if node.Func != nil {
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
rv := make([]string, 0, len(node.Children))
|
||||
for childName := range node.Children {
|
||||
rv = append(rv, childName)
|
||||
}
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
type bintree struct {
|
||||
Func func() (*asset, error)
|
||||
Children map[string]*bintree
|
||||
}
|
||||
|
||||
var _bintree = &bintree{nil, map[string]*bintree{
|
||||
"kustomizationapi": &bintree{nil, map[string]*bintree{
|
||||
"swagger.json": &bintree{kustomizationapiSwaggerJson, map[string]*bintree{}},
|
||||
}},
|
||||
}}
|
||||
|
||||
// RestoreAsset restores an asset under the given directory
|
||||
func RestoreAsset(dir, name string) error {
|
||||
data, err := Asset(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info, err := AssetInfo(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RestoreAssets restores an asset under the given directory recursively
|
||||
func RestoreAssets(dir, name string) error {
|
||||
children, err := AssetDir(name)
|
||||
// File
|
||||
if err != nil {
|
||||
return RestoreAsset(dir, name)
|
||||
}
|
||||
// Dir
|
||||
for _, child := range children {
|
||||
err = RestoreAssets(dir, filepath.Join(name, child))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func _filePath(dir, name string) string {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
|
||||
}
|
||||
130
vendor/sigs.k8s.io/kustomize/kyaml/openapi/kustomizationapi/swagger.json
generated
vendored
Normal file
130
vendor/sigs.k8s.io/kustomize/kyaml/openapi/kustomizationapi/swagger.json
generated
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
{
|
||||
"definitions": {
|
||||
"io.k8s.api.apps.v1.ConfigMapArgs": {
|
||||
"properties": {
|
||||
"GeneratorArgs": {
|
||||
"$ref": "#/definitions/io.k8s.api.apps.v1.GeneratorArgs"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "kustomize.config.k8s.io",
|
||||
"kind": "ConfigMapArgs",
|
||||
"version": "v1beta1"
|
||||
}
|
||||
]
|
||||
},
|
||||
"io.k8s.api.apps.v1.SecretArgs": {
|
||||
"properties": {
|
||||
"GeneratorArgs": {
|
||||
"$ref": "#/definitions/io.k8s.api.apps.v1.GeneratorArgs"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "kustomize.config.k8s.io",
|
||||
"kind": "SecretArgs",
|
||||
"version": "v1beta1"
|
||||
}
|
||||
]
|
||||
},
|
||||
"io.k8s.api.apps.v1.GeneratorArgs": {
|
||||
"properties": {
|
||||
"namespace": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"behavior": {
|
||||
"type": "string"
|
||||
},
|
||||
"KvPairSources": {
|
||||
"$ref": "#/definitions/io.k8s.api.apps.v1.KvPairSources"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "kustomize.config.k8s.io",
|
||||
"kind": "GeneratorArgs",
|
||||
"version": "v1beta1"
|
||||
}
|
||||
]
|
||||
},
|
||||
"io.k8s.api.apps.v1.Kustomization": {
|
||||
"required": [
|
||||
"TypeMeta"
|
||||
],
|
||||
"properties": {
|
||||
"configMapGenerator": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/io.k8s.api.apps.v1.ConfigMapArgs"
|
||||
},
|
||||
"type": "array",
|
||||
"x-kubernetes-patch-merge-key": "name",
|
||||
"x-kubernetes-patch-strategy": "merge"
|
||||
},
|
||||
"secretGenerator": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/io.k8s.api.apps.v1.SecretArgs"
|
||||
},
|
||||
"type": "array",
|
||||
"x-kubernetes-patch-merge-key": "name",
|
||||
"x-kubernetes-patch-strategy": "merge"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "kustomize.config.k8s.io",
|
||||
"kind": "Kustomization",
|
||||
"version": "v1beta1"
|
||||
}
|
||||
]
|
||||
},
|
||||
"io.k8s.api.apps.v1.KvPairSources": {
|
||||
"properties": {
|
||||
"literals": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"files": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"envs": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"env": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "kustomize.config.k8s.io",
|
||||
"kind": "KvPairSources",
|
||||
"version": "v1beta1"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
607
vendor/sigs.k8s.io/kustomize/kyaml/openapi/openapi.go
generated
vendored
Normal file
607
vendor/sigs.k8s.io/kustomize/kyaml/openapi/openapi.go
generated
vendored
Normal file
@@ -0,0 +1,607 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package openapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/spec"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi"
|
||||
"sigs.k8s.io/kustomize/kyaml/openapi/kustomizationapi"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
// globalSchema contains global state information about the openapi
|
||||
var globalSchema openapiData
|
||||
|
||||
// kubernetesOpenAPIVersion specifies which builtin kubernetes schema to use
|
||||
var kubernetesOpenAPIVersion string
|
||||
|
||||
// customSchemaFile stores the custom OpenApi schema if it is provided
|
||||
var customSchema []byte
|
||||
|
||||
// openapiData contains the parsed openapi state. this is in a struct rather than
|
||||
// a list of vars so that it can be reset from tests.
|
||||
type openapiData struct {
|
||||
// schema holds the OpenAPI schema data
|
||||
schema spec.Schema
|
||||
|
||||
// schemaForResourceType is a map of Resource types to their schemas
|
||||
schemaByResourceType map[yaml.TypeMeta]*spec.Schema
|
||||
|
||||
// namespaceabilityByResourceType stores whether a given Resource type
|
||||
// is namespaceable or not
|
||||
namespaceabilityByResourceType map[yaml.TypeMeta]bool
|
||||
|
||||
// noUseBuiltInSchema stores whether we want to prevent using the built-n
|
||||
// Kubernetes schema as part of the global schema
|
||||
noUseBuiltInSchema bool
|
||||
|
||||
// schemaInit stores whether or not we've parsed the schema already,
|
||||
// so that we only reparse the when necessary (to speed up performance)
|
||||
schemaInit bool
|
||||
}
|
||||
|
||||
// ResourceSchema wraps the OpenAPI Schema.
|
||||
type ResourceSchema struct {
|
||||
// Schema is the OpenAPI schema for a Resource or field
|
||||
Schema *spec.Schema
|
||||
}
|
||||
|
||||
// IsEmpty returns true if the ResourceSchema is empty
|
||||
func (rs *ResourceSchema) IsMissingOrNull() bool {
|
||||
if rs == nil || rs.Schema == nil {
|
||||
return true
|
||||
}
|
||||
return reflect.DeepEqual(*rs.Schema, spec.Schema{})
|
||||
}
|
||||
|
||||
// SchemaForResourceType returns the Schema for the given Resource
|
||||
// TODO(pwittrock): create a version of this function that will return a schema
|
||||
// which can be used for duck-typed Resources -- e.g. contains common fields such
|
||||
// as metadata, replicas and spec.template.spec
|
||||
func SchemaForResourceType(t yaml.TypeMeta) *ResourceSchema {
|
||||
initSchema()
|
||||
rs, found := globalSchema.schemaByResourceType[t]
|
||||
if !found {
|
||||
return nil
|
||||
}
|
||||
return &ResourceSchema{Schema: rs}
|
||||
}
|
||||
|
||||
// SupplementaryOpenAPIFieldName is the conventional field name (JSON/YAML) containing
|
||||
// supplementary OpenAPI definitions.
|
||||
const SupplementaryOpenAPIFieldName = "openAPI"
|
||||
|
||||
const Definitions = "definitions"
|
||||
|
||||
// AddSchemaFromFile reads the file at path and parses the OpenAPI definitions
|
||||
// from the field "openAPI", also returns a function to clean the added definitions
|
||||
// The returned clean function is a no-op on error, or else it's a function
|
||||
// that the caller should use to remove the added openAPI definitions from
|
||||
// global schema
|
||||
func SchemaFromFile(path string) (*spec.Schema, error) {
|
||||
object, err := parseOpenAPI(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return schemaUsingField(object, SupplementaryOpenAPIFieldName)
|
||||
}
|
||||
|
||||
// DefinitionRefs returns the list of openAPI definition references present in the
|
||||
// input openAPIPath
|
||||
func DefinitionRefs(openAPIPath string) ([]string, error) {
|
||||
object, err := parseOpenAPI(openAPIPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return definitionRefsFromRNode(object)
|
||||
}
|
||||
|
||||
// definitionRefsFromRNode returns the list of openAPI definitions keys from input
|
||||
// yaml RNode
|
||||
func definitionRefsFromRNode(object *yaml.RNode) ([]string, error) {
|
||||
definitions, err := object.Pipe(yaml.Lookup(SupplementaryOpenAPIFieldName, Definitions))
|
||||
if definitions == nil {
|
||||
return nil, err
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return definitions.Fields()
|
||||
}
|
||||
|
||||
// parseOpenAPI reads openAPIPath yaml and converts it to RNode
|
||||
func parseOpenAPI(openAPIPath string) (*yaml.RNode, error) {
|
||||
b, err := ioutil.ReadFile(openAPIPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
object, err := yaml.Parse(string(b))
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("invalid file %q: %v", openAPIPath, err)
|
||||
}
|
||||
return object, nil
|
||||
}
|
||||
|
||||
// addSchemaUsingField parses the OpenAPI definitions from the specified field.
|
||||
// If field is the empty string, use the whole document as OpenAPI.
|
||||
func schemaUsingField(object *yaml.RNode, field string) (*spec.Schema, error) {
|
||||
if field != "" {
|
||||
// get the field containing the openAPI
|
||||
m := object.Field(field)
|
||||
if m.IsNilOrEmpty() {
|
||||
// doesn't contain openAPI definitions
|
||||
return nil, nil
|
||||
}
|
||||
object = m.Value
|
||||
}
|
||||
|
||||
oAPI, err := object.String()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// convert the yaml openAPI to a JSON string by unmarshalling it to an
|
||||
// interface{} and the marshalling it to a string
|
||||
var o interface{}
|
||||
err = yaml.Unmarshal([]byte(oAPI), &o)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
j, err := json.Marshal(o)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var sc spec.Schema
|
||||
err = sc.UnmarshalJSON(j)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &sc, nil
|
||||
}
|
||||
|
||||
// AddSchema parses s, and adds definitions from s to the global schema.
|
||||
func AddSchema(s []byte) error {
|
||||
return parse(s)
|
||||
}
|
||||
|
||||
// ResetOpenAPI resets the openapi data to empty
|
||||
func ResetOpenAPI() {
|
||||
globalSchema = openapiData{}
|
||||
}
|
||||
|
||||
// AddDefinitions adds the definitions to the global schema.
|
||||
func AddDefinitions(definitions spec.Definitions) {
|
||||
// initialize values if they have not yet been set
|
||||
if globalSchema.schemaByResourceType == nil {
|
||||
globalSchema.schemaByResourceType = map[yaml.TypeMeta]*spec.Schema{}
|
||||
}
|
||||
if globalSchema.schema.Definitions == nil {
|
||||
globalSchema.schema.Definitions = spec.Definitions{}
|
||||
}
|
||||
|
||||
// index the schema definitions so we can lookup them up for Resources
|
||||
for k := range definitions {
|
||||
// index by GVK, if no GVK is found then it is the schema for a subfield
|
||||
// of a Resource
|
||||
d := definitions[k]
|
||||
|
||||
// copy definitions to the schema
|
||||
globalSchema.schema.Definitions[k] = d
|
||||
gvk, found := d.VendorExtensible.Extensions[kubernetesGVKExtensionKey]
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
// cast the extension to a []map[string]string
|
||||
exts, ok := gvk.([]interface{})
|
||||
if !ok || len(exts) != 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
typeMeta, ok := toTypeMeta(exts[0])
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
globalSchema.schemaByResourceType[typeMeta] = &d
|
||||
}
|
||||
}
|
||||
|
||||
func toTypeMeta(ext interface{}) (yaml.TypeMeta, bool) {
|
||||
m, ok := ext.(map[string]interface{})
|
||||
if !ok {
|
||||
return yaml.TypeMeta{}, false
|
||||
}
|
||||
|
||||
g := m[groupKey].(string)
|
||||
apiVersion := m[versionKey].(string)
|
||||
if g != "" {
|
||||
apiVersion = g + "/" + apiVersion
|
||||
}
|
||||
return yaml.TypeMeta{Kind: m[kindKey].(string), APIVersion: apiVersion}, true
|
||||
}
|
||||
|
||||
// Resolve resolves the reference against the global schema
|
||||
func Resolve(ref *spec.Ref, schema *spec.Schema) (*spec.Schema, error) {
|
||||
return resolve(schema, ref)
|
||||
}
|
||||
|
||||
// Schema returns the global schema
|
||||
func Schema() *spec.Schema {
|
||||
return rootSchema()
|
||||
}
|
||||
|
||||
// GetSchema parses s into a ResourceSchema, resolving References within the
|
||||
// global schema.
|
||||
func GetSchema(s string, schema *spec.Schema) (*ResourceSchema, error) {
|
||||
var sc spec.Schema
|
||||
if err := sc.UnmarshalJSON([]byte(s)); err != nil {
|
||||
return nil, errors.Wrap(err)
|
||||
}
|
||||
if sc.Ref.String() != "" {
|
||||
r, err := Resolve(&sc.Ref, schema)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err)
|
||||
}
|
||||
sc = *r
|
||||
}
|
||||
|
||||
return &ResourceSchema{Schema: &sc}, nil
|
||||
}
|
||||
|
||||
// IsNamespaceScoped determines whether a resource is namespace or
|
||||
// cluster-scoped by looking at the information in the openapi schema.
|
||||
// The second return value tells whether the provided type could be found
|
||||
// in the openapi schema. If the value is false here, the scope of the
|
||||
// resource is not known. If the type if found, the first return value will
|
||||
// be true if the resource is namespace-scoped, and false if the type is
|
||||
// cluster-scoped.
|
||||
func IsNamespaceScoped(typeMeta yaml.TypeMeta) (bool, bool) {
|
||||
initSchema()
|
||||
isNamespaceScoped, found := globalSchema.namespaceabilityByResourceType[typeMeta]
|
||||
return isNamespaceScoped, found
|
||||
}
|
||||
|
||||
// SuppressBuiltInSchemaUse can be called to prevent using the built-in Kubernetes
|
||||
// schema as part of the global schema.
|
||||
// Must be called before the schema is used.
|
||||
func SuppressBuiltInSchemaUse() {
|
||||
globalSchema.noUseBuiltInSchema = true
|
||||
}
|
||||
|
||||
// Elements returns the Schema for the elements of an array.
|
||||
func (rs *ResourceSchema) Elements() *ResourceSchema {
|
||||
// load the schema from swagger.json
|
||||
initSchema()
|
||||
|
||||
if len(rs.Schema.Type) != 1 || rs.Schema.Type[0] != "array" {
|
||||
// either not an array, or array has multiple types
|
||||
return nil
|
||||
}
|
||||
if rs == nil || rs.Schema == nil || rs.Schema.Items == nil {
|
||||
// no-scheme for the items
|
||||
return nil
|
||||
}
|
||||
s := *rs.Schema.Items.Schema
|
||||
for s.Ref.String() != "" {
|
||||
sc, e := Resolve(&s.Ref, Schema())
|
||||
if e != nil {
|
||||
return nil
|
||||
}
|
||||
s = *sc
|
||||
}
|
||||
return &ResourceSchema{Schema: &s}
|
||||
}
|
||||
|
||||
const Elements = "[]"
|
||||
|
||||
// Lookup calls either Field or Elements for each item in the path.
|
||||
// If the path item is "[]", then Elements is called, otherwise
|
||||
// Field is called.
|
||||
// If any Field or Elements call returns nil, then Lookup returns
|
||||
// nil immediately.
|
||||
func (rs *ResourceSchema) Lookup(path ...string) *ResourceSchema {
|
||||
s := rs
|
||||
for _, p := range path {
|
||||
if s == nil {
|
||||
break
|
||||
}
|
||||
if p == Elements {
|
||||
s = s.Elements()
|
||||
continue
|
||||
}
|
||||
s = s.Field(p)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Field returns the Schema for a field.
|
||||
func (rs *ResourceSchema) Field(field string) *ResourceSchema {
|
||||
// load the schema from swagger.json
|
||||
initSchema()
|
||||
|
||||
// locate the Schema
|
||||
s, found := rs.Schema.Properties[field]
|
||||
switch {
|
||||
case found:
|
||||
// no-op, continue with s as the schema
|
||||
case rs.Schema.AdditionalProperties != nil && rs.Schema.AdditionalProperties.Schema != nil:
|
||||
// map field type -- use Schema of the value
|
||||
// (the key doesn't matter, they all have the same value type)
|
||||
s = *rs.Schema.AdditionalProperties.Schema
|
||||
default:
|
||||
// no Schema found from either swagger.json or line comments
|
||||
return nil
|
||||
}
|
||||
|
||||
// resolve the reference to the Schema if the Schema has one
|
||||
for s.Ref.String() != "" {
|
||||
sc, e := Resolve(&s.Ref, Schema())
|
||||
if e != nil {
|
||||
return nil
|
||||
}
|
||||
s = *sc
|
||||
}
|
||||
|
||||
// return the merged Schema
|
||||
return &ResourceSchema{Schema: &s}
|
||||
}
|
||||
|
||||
// PatchStrategyAndKeyList returns the patch strategy and complete merge key list
|
||||
func (rs *ResourceSchema) PatchStrategyAndKeyList() (string, []string) {
|
||||
ps, found := rs.Schema.Extensions[kubernetesPatchStrategyExtensionKey]
|
||||
if !found {
|
||||
// empty patch strategy
|
||||
return "", []string{}
|
||||
}
|
||||
mkList, found := rs.Schema.Extensions[kubernetesMergeKeyMapList]
|
||||
if found {
|
||||
// mkList is []interface, convert to []string
|
||||
mkListStr := make([]string, len(mkList.([]interface{})))
|
||||
for i, v := range mkList.([]interface{}) {
|
||||
mkListStr[i] = v.(string)
|
||||
}
|
||||
return ps.(string), mkListStr
|
||||
}
|
||||
mk, found := rs.Schema.Extensions[kubernetesMergeKeyExtensionKey]
|
||||
if !found {
|
||||
// no mergeKey -- may be a primitive associative list (e.g. finalizers)
|
||||
return ps.(string), []string{}
|
||||
}
|
||||
return ps.(string), []string{mk.(string)}
|
||||
}
|
||||
|
||||
// PatchStrategyAndKey returns the patch strategy and merge key extensions
|
||||
func (rs *ResourceSchema) PatchStrategyAndKey() (string, string) {
|
||||
ps, found := rs.Schema.Extensions[kubernetesPatchStrategyExtensionKey]
|
||||
if !found {
|
||||
// empty patch strategy
|
||||
return "", ""
|
||||
}
|
||||
|
||||
mk, found := rs.Schema.Extensions[kubernetesMergeKeyExtensionKey]
|
||||
if !found {
|
||||
// no mergeKey -- may be a primitive associative list (e.g. finalizers)
|
||||
mk = ""
|
||||
}
|
||||
return ps.(string), mk.(string)
|
||||
}
|
||||
|
||||
const (
|
||||
// kubernetesOpenAPIDefaultVersion is the latest version number of the statically compiled in
|
||||
// OpenAPI schema for kubernetes built-in types
|
||||
kubernetesOpenAPIDefaultVersion = kubernetesapi.DefaultOpenAPI
|
||||
|
||||
// kustomizationAPIAssetName is the name of the asset containing the statically compiled in
|
||||
// OpenAPI definitions for Kustomization built-in types
|
||||
kustomizationAPIAssetName = "kustomizationapi/swagger.json"
|
||||
|
||||
// kubernetesGVKExtensionKey is the key to lookup the kubernetes group version kind extension
|
||||
// -- the extension is an array of objects containing a gvk
|
||||
kubernetesGVKExtensionKey = "x-kubernetes-group-version-kind"
|
||||
|
||||
// kubernetesMergeKeyExtensionKey is the key to lookup the kubernetes merge key extension
|
||||
// -- the extension is a string
|
||||
kubernetesMergeKeyExtensionKey = "x-kubernetes-patch-merge-key"
|
||||
|
||||
// kubernetesPatchStrategyExtensionKey is the key to lookup the kubernetes patch strategy
|
||||
// extension -- the extension is a string
|
||||
kubernetesPatchStrategyExtensionKey = "x-kubernetes-patch-strategy"
|
||||
|
||||
// kubernetesMergeKeyMapList is the list of merge keys when there needs to be multiple
|
||||
// -- the extension is an array of strings
|
||||
kubernetesMergeKeyMapList = "x-kubernetes-list-map-keys"
|
||||
|
||||
// groupKey is the key to lookup the group from the GVK extension
|
||||
groupKey = "group"
|
||||
// versionKey is the key to lookup the version from the GVK extension
|
||||
versionKey = "version"
|
||||
// kindKey is the the to lookup the kind from the GVK extension
|
||||
kindKey = "kind"
|
||||
)
|
||||
|
||||
// SetSchema sets the kubernetes OpenAPI schema version to use
|
||||
func SetSchema(openAPIField map[string]string, schema []byte, reset bool) error {
|
||||
// this should only be set once
|
||||
schemaIsSet := (kubernetesOpenAPIVersion != "") || customSchema != nil
|
||||
if schemaIsSet && !reset {
|
||||
return nil
|
||||
}
|
||||
|
||||
version, exists := openAPIField["version"]
|
||||
if exists && schema != nil {
|
||||
return fmt.Errorf("builtin version and custom schema provided, cannot use both")
|
||||
}
|
||||
|
||||
if schema != nil { // use custom schema
|
||||
customSchema = schema
|
||||
kubernetesOpenAPIVersion = "custom"
|
||||
return nil
|
||||
}
|
||||
|
||||
// use builtin version
|
||||
kubernetesOpenAPIVersion = strings.ReplaceAll(version, ".", "")
|
||||
if kubernetesOpenAPIVersion == "" {
|
||||
return nil
|
||||
}
|
||||
if _, ok := kubernetesapi.OpenAPIMustAsset[kubernetesOpenAPIVersion]; !ok {
|
||||
return fmt.Errorf("the specified OpenAPI version is not built in")
|
||||
}
|
||||
customSchema = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSchemaVersion returns what kubernetes OpenAPI version is being used
|
||||
func GetSchemaVersion() string {
|
||||
switch {
|
||||
case kubernetesOpenAPIVersion == "" && customSchema == nil:
|
||||
return kubernetesOpenAPIDefaultVersion
|
||||
case customSchema != nil:
|
||||
return "using custom schema from file provided"
|
||||
default:
|
||||
return kubernetesOpenAPIVersion
|
||||
}
|
||||
}
|
||||
|
||||
// initSchema parses the json schema
|
||||
func initSchema() {
|
||||
if globalSchema.schemaInit {
|
||||
return
|
||||
}
|
||||
globalSchema.schemaInit = true
|
||||
|
||||
if customSchema != nil {
|
||||
err := parse(customSchema)
|
||||
if err != nil {
|
||||
panic("invalid schema file")
|
||||
}
|
||||
if err = parse(kustomizationapi.MustAsset(kustomizationAPIAssetName)); err != nil {
|
||||
// this should never happen
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if kubernetesOpenAPIVersion == "" {
|
||||
parseBuiltinSchema(kubernetesOpenAPIDefaultVersion)
|
||||
} else {
|
||||
parseBuiltinSchema(kubernetesOpenAPIVersion)
|
||||
}
|
||||
}
|
||||
|
||||
// parseBuiltinSchema calls parse to parse the json schemas
|
||||
func parseBuiltinSchema(version string) {
|
||||
if globalSchema.noUseBuiltInSchema {
|
||||
// don't parse the built in schema
|
||||
return
|
||||
}
|
||||
|
||||
// parse the swagger, this should never fail
|
||||
assetName := filepath.Join(
|
||||
"kubernetesapi",
|
||||
version,
|
||||
"swagger.json")
|
||||
|
||||
if err := parse(kubernetesapi.OpenAPIMustAsset[version](assetName)); err != nil {
|
||||
// this should never happen
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := parse(kustomizationapi.MustAsset(kustomizationAPIAssetName)); err != nil {
|
||||
// this should never happen
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// parse parses and indexes a single json schema
|
||||
func parse(b []byte) error {
|
||||
var swagger spec.Swagger
|
||||
|
||||
if err := swagger.UnmarshalJSON(b); err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
AddDefinitions(swagger.Definitions)
|
||||
findNamespaceability(swagger.Paths)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// findNamespaceability looks at the api paths for the resource to determine
|
||||
// if it is cluster-scoped or namespace-scoped. The gvk of the resource
|
||||
// for each path is found by looking at the x-kubernetes-group-version-kind
|
||||
// extension. If a path exists for the resource that contains a namespace path
|
||||
// parameter, the resource is namespace-scoped.
|
||||
func findNamespaceability(paths *spec.Paths) {
|
||||
if globalSchema.namespaceabilityByResourceType == nil {
|
||||
globalSchema.namespaceabilityByResourceType = make(map[yaml.TypeMeta]bool)
|
||||
}
|
||||
|
||||
if paths == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for path, pathInfo := range paths.Paths {
|
||||
if pathInfo.Get == nil {
|
||||
continue
|
||||
}
|
||||
gvk, found := pathInfo.Get.VendorExtensible.Extensions[kubernetesGVKExtensionKey]
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
typeMeta, found := toTypeMeta(gvk)
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.Contains(path, "namespaces/{namespace}") {
|
||||
// if we find a namespace path parameter, we just update the map
|
||||
// directly
|
||||
globalSchema.namespaceabilityByResourceType[typeMeta] = true
|
||||
} else if _, found := globalSchema.namespaceabilityByResourceType[typeMeta]; !found {
|
||||
// if the resource doesn't have the namespace path parameter, we
|
||||
// only add it to the map if it doesn't already exist.
|
||||
globalSchema.namespaceabilityByResourceType[typeMeta] = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func resolve(root interface{}, ref *spec.Ref) (*spec.Schema, error) {
|
||||
res, _, err := ref.GetPointer().Get(root)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err)
|
||||
}
|
||||
switch sch := res.(type) {
|
||||
case spec.Schema:
|
||||
return &sch, nil
|
||||
case *spec.Schema:
|
||||
return sch, nil
|
||||
case map[string]interface{}:
|
||||
b, err := json.Marshal(sch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newSch := new(spec.Schema)
|
||||
if err = json.Unmarshal(b, newSch); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newSch, nil
|
||||
default:
|
||||
return nil, errors.Wrap(fmt.Errorf("unknown type for the resolved reference"))
|
||||
}
|
||||
}
|
||||
|
||||
func rootSchema() *spec.Schema {
|
||||
initSchema()
|
||||
return &globalSchema.schema
|
||||
}
|
||||
64
vendor/sigs.k8s.io/kustomize/kyaml/sets/string.go
generated
vendored
Normal file
64
vendor/sigs.k8s.io/kustomize/kyaml/sets/string.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sets
|
||||
|
||||
type String map[string]interface{}
|
||||
|
||||
func (s String) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s String) List() []string {
|
||||
var val []string
|
||||
for k := range s {
|
||||
val = append(val, k)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
func (s String) Has(val string) bool {
|
||||
_, found := s[val]
|
||||
return found
|
||||
}
|
||||
|
||||
func (s String) Insert(vals ...string) {
|
||||
for _, val := range vals {
|
||||
s[val] = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s String) Difference(s2 String) String {
|
||||
s3 := String{}
|
||||
for k := range s {
|
||||
if _, found := s2[k]; !found {
|
||||
s3.Insert(k)
|
||||
}
|
||||
}
|
||||
return s3
|
||||
}
|
||||
|
||||
func (s String) SymmetricDifference(s2 String) String {
|
||||
s3 := String{}
|
||||
for k := range s {
|
||||
if _, found := s2[k]; !found {
|
||||
s3.Insert(k)
|
||||
}
|
||||
}
|
||||
for k := range s2 {
|
||||
if _, found := s[k]; !found {
|
||||
s3.Insert(k)
|
||||
}
|
||||
}
|
||||
return s3
|
||||
}
|
||||
|
||||
func (s String) Intersection(s2 String) String {
|
||||
s3 := String{}
|
||||
for k := range s {
|
||||
if _, found := s2[k]; found {
|
||||
s3.Insert(k)
|
||||
}
|
||||
}
|
||||
return s3
|
||||
}
|
||||
44
vendor/sigs.k8s.io/kustomize/kyaml/sets/stringlist.go
generated
vendored
Normal file
44
vendor/sigs.k8s.io/kustomize/kyaml/sets/stringlist.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sets
|
||||
|
||||
// StringList is a set, where each element of
|
||||
// the set is a string slice.
|
||||
type StringList [][]string
|
||||
|
||||
func (s StringList) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s StringList) Insert(val []string) StringList {
|
||||
if !s.Has(val) {
|
||||
return append(s, val)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s StringList) Has(val []string) bool {
|
||||
if len(s) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := range s {
|
||||
if isStringSliceEqual(s[i], val) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isStringSliceEqual(s []string, t []string) bool {
|
||||
if len(s) != len(t) {
|
||||
return false
|
||||
}
|
||||
for i := range s {
|
||||
if s[i] != t[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
44
vendor/sigs.k8s.io/kustomize/kyaml/yaml/alias.go
generated
vendored
Normal file
44
vendor/sigs.k8s.io/kustomize/kyaml/yaml/alias.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Expose the yaml.v3 functions so this package can be used as a replacement
|
||||
|
||||
type Decoder = yaml.Decoder
|
||||
type Encoder = yaml.Encoder
|
||||
type IsZeroer = yaml.IsZeroer
|
||||
type Kind = yaml.Kind
|
||||
type Marshaler = yaml.Marshaler
|
||||
type Node = yaml.Node
|
||||
type Style = yaml.Style
|
||||
type TypeError = yaml.TypeError
|
||||
type Unmarshaler = yaml.Unmarshaler
|
||||
|
||||
var Marshal = yaml.Marshal
|
||||
var Unmarshal = yaml.Unmarshal
|
||||
var NewDecoder = yaml.NewDecoder
|
||||
var NewEncoder = func(w io.Writer) *yaml.Encoder {
|
||||
e := yaml.NewEncoder(w)
|
||||
e.SetIndent(2)
|
||||
return e
|
||||
}
|
||||
|
||||
var AliasNode yaml.Kind = yaml.AliasNode
|
||||
var DocumentNode yaml.Kind = yaml.DocumentNode
|
||||
var MappingNode yaml.Kind = yaml.MappingNode
|
||||
var ScalarNode yaml.Kind = yaml.ScalarNode
|
||||
var SequenceNode yaml.Kind = yaml.SequenceNode
|
||||
|
||||
var DoubleQuotedStyle yaml.Style = yaml.DoubleQuotedStyle
|
||||
var FlowStyle yaml.Style = yaml.FlowStyle
|
||||
var FoldedStyle yaml.Style = yaml.FoldedStyle
|
||||
var LiteralStyle yaml.Style = yaml.LiteralStyle
|
||||
var SingleQuotedStyle yaml.Style = yaml.SingleQuotedStyle
|
||||
var TaggedStyle yaml.Style = yaml.TaggedStyle
|
||||
92
vendor/sigs.k8s.io/kustomize/kyaml/yaml/compatibility.go
generated
vendored
Normal file
92
vendor/sigs.k8s.io/kustomize/kyaml/yaml/compatibility.go
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/spec"
|
||||
y1_1 "gopkg.in/yaml.v2"
|
||||
y1_2 "gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// typeToTag maps OpenAPI schema types to yaml 1.2 tags
|
||||
var typeToTag = map[string]string{
|
||||
"string": NodeTagString,
|
||||
"integer": NodeTagInt,
|
||||
"boolean": NodeTagBool,
|
||||
"number": NodeTagFloat,
|
||||
}
|
||||
|
||||
// FormatNonStringStyle makes sure that values which parse as non-string values in yaml 1.1
|
||||
// are correctly formatted given the Schema type.
|
||||
func FormatNonStringStyle(node *Node, schema spec.Schema) {
|
||||
if len(schema.Type) != 1 {
|
||||
return
|
||||
}
|
||||
t := schema.Type[0]
|
||||
|
||||
if !IsYaml1_1NonString(node) {
|
||||
return
|
||||
}
|
||||
switch {
|
||||
case t == "string" && schema.Format != "int-or-string":
|
||||
if (node.Style&DoubleQuotedStyle == 0) && (node.Style&SingleQuotedStyle == 0) {
|
||||
// must quote values so they are parsed as strings
|
||||
node.Style = DoubleQuotedStyle
|
||||
}
|
||||
case t == "boolean" || t == "integer" || t == "number":
|
||||
if (node.Style&DoubleQuotedStyle != 0) || (node.Style&SingleQuotedStyle != 0) {
|
||||
// must NOT quote the values so they aren't parsed as strings
|
||||
node.Style = 0
|
||||
}
|
||||
default:
|
||||
return
|
||||
}
|
||||
if tag, found := typeToTag[t]; found {
|
||||
// make sure the right tag is set
|
||||
node.Tag = tag
|
||||
}
|
||||
}
|
||||
|
||||
// IsYaml1_1NonString returns true if the value parses as a non-string value in yaml 1.1
|
||||
// when unquoted.
|
||||
//
|
||||
// Note: yaml 1.2 uses different keywords than yaml 1.1. Example: yaml 1.2 interprets
|
||||
// `field: on` and `field: "on"` as equivalent (both strings). However Yaml 1.1 interprets
|
||||
// `field: on` as on being a bool and `field: "on"` as on being a string.
|
||||
// If an input is read with `field: "on"`, and the style is changed from DoubleQuote to 0,
|
||||
// it will change the type of the field from a string to a bool. For this reason, fields
|
||||
// which are keywords in yaml 1.1 should never have their style changed, as it would break
|
||||
// backwards compatibility with yaml 1.1 -- which is what is used by the Kubernetes apiserver.
|
||||
func IsYaml1_1NonString(node *Node) bool {
|
||||
if node.Kind != y1_2.ScalarNode {
|
||||
// not a keyword
|
||||
return false
|
||||
}
|
||||
return IsValueNonString(node.Value)
|
||||
}
|
||||
|
||||
func IsValueNonString(value string) bool {
|
||||
if value == "" {
|
||||
return false
|
||||
}
|
||||
if strings.Contains(value, "\n") {
|
||||
// multi-line strings will fail to unmarshal
|
||||
return false
|
||||
}
|
||||
// check if the value will unmarshal into a non-string value using a yaml 1.1 parser
|
||||
var i1 interface{}
|
||||
if err := y1_1.Unmarshal([]byte(value), &i1); err != nil {
|
||||
return false
|
||||
}
|
||||
if reflect.TypeOf(i1) != stringType {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var stringType = reflect.TypeOf("string")
|
||||
30
vendor/sigs.k8s.io/kustomize/kyaml/yaml/const.go
generated
vendored
Normal file
30
vendor/sigs.k8s.io/kustomize/kyaml/yaml/const.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
const (
|
||||
// NodeTagNull is the tag set for a yaml.Document that contains no data;
|
||||
// e.g. it isn't a Map, Slice, Document, etc
|
||||
NodeTagNull = "!!null"
|
||||
NodeTagFloat = "!!float"
|
||||
NodeTagString = "!!str"
|
||||
NodeTagBool = "!!bool"
|
||||
NodeTagInt = "!!int"
|
||||
NodeTagMap = "!!map"
|
||||
NodeTagSeq = "!!seq"
|
||||
NodeTagEmpty = ""
|
||||
)
|
||||
|
||||
// Field names
|
||||
const (
|
||||
AnnotationsField = "annotations"
|
||||
APIVersionField = "apiVersion"
|
||||
KindField = "kind"
|
||||
MetadataField = "metadata"
|
||||
DataField = "data"
|
||||
BinaryDataField = "binaryData"
|
||||
NameField = "name"
|
||||
NamespaceField = "namespace"
|
||||
LabelsField = "labels"
|
||||
)
|
||||
121
vendor/sigs.k8s.io/kustomize/kyaml/yaml/datamap.go
generated
vendored
Normal file
121
vendor/sigs.k8s.io/kustomize/kyaml/yaml/datamap.go
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"sort"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// SortedMapKeys returns a sorted slice of keys to the given map.
|
||||
// Writing this function never gets old.
|
||||
func SortedMapKeys(m map[string]string) []string {
|
||||
keys := make([]string, len(m))
|
||||
i := 0
|
||||
for k := range m {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
||||
func (rn *RNode) LoadMapIntoConfigMapData(m map[string]string) error {
|
||||
for _, k := range SortedMapKeys(m) {
|
||||
fldName, vrN := makeConfigMapValueRNode(m[k])
|
||||
if _, err := rn.Pipe(
|
||||
LookupCreate(MappingNode, fldName),
|
||||
SetField(k, vrN)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rn *RNode) LoadMapIntoConfigMapBinaryData(m map[string]string) error {
|
||||
for _, k := range SortedMapKeys(m) {
|
||||
_, vrN := makeConfigMapValueRNode(m[k])
|
||||
// we know this is binary data
|
||||
fldName := BinaryDataField
|
||||
if _, err := rn.Pipe(
|
||||
LookupCreate(MappingNode, fldName),
|
||||
SetField(k, vrN)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeConfigMapValueRNode(s string) (field string, rN *RNode) {
|
||||
yN := &Node{Kind: ScalarNode}
|
||||
yN.Tag = NodeTagString
|
||||
if utf8.ValidString(s) {
|
||||
field = DataField
|
||||
yN.Value = s
|
||||
} else {
|
||||
field = BinaryDataField
|
||||
yN.Value = encodeBase64(s)
|
||||
}
|
||||
if strings.Contains(yN.Value, "\n") {
|
||||
yN.Style = LiteralStyle
|
||||
}
|
||||
return field, NewRNode(yN)
|
||||
}
|
||||
|
||||
func (rn *RNode) LoadMapIntoSecretData(m map[string]string) error {
|
||||
mapNode, err := rn.Pipe(LookupCreate(MappingNode, DataField))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, k := range SortedMapKeys(m) {
|
||||
vrN := makeSecretValueRNode(m[k])
|
||||
if _, err := mapNode.Pipe(SetField(k, vrN)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// In a secret, all data is base64 encoded, regardless of its conformance
|
||||
// or lack thereof to UTF-8.
|
||||
func makeSecretValueRNode(s string) *RNode {
|
||||
yN := &Node{Kind: ScalarNode}
|
||||
// Purposely don't use YAML tags to identify the data as being plain text or
|
||||
// binary. It kubernetes Secrets the values in the `data` map are expected
|
||||
// to be base64 encoded, and in ConfigMaps that same can be said for the
|
||||
// values in the `binaryData` field.
|
||||
yN.Tag = NodeTagString
|
||||
yN.Value = encodeBase64(s)
|
||||
if strings.Contains(yN.Value, "\n") {
|
||||
yN.Style = LiteralStyle
|
||||
}
|
||||
return NewRNode(yN)
|
||||
}
|
||||
|
||||
// encodeBase64 encodes s as base64 that is broken up into multiple lines
|
||||
// as appropriate for the resulting length.
|
||||
func encodeBase64(s string) string {
|
||||
const lineLen = 70
|
||||
encLen := base64.StdEncoding.EncodedLen(len(s))
|
||||
lines := encLen/lineLen + 1
|
||||
buf := make([]byte, encLen*2+lines)
|
||||
in := buf[0:encLen]
|
||||
out := buf[encLen:]
|
||||
base64.StdEncoding.Encode(in, []byte(s))
|
||||
k := 0
|
||||
for i := 0; i < len(in); i += lineLen {
|
||||
j := i + lineLen
|
||||
if j > len(in) {
|
||||
j = len(in)
|
||||
}
|
||||
k += copy(out[k:], in[i:j])
|
||||
if lines > 1 {
|
||||
out[k] = '\n'
|
||||
k++
|
||||
}
|
||||
}
|
||||
return string(out[:k])
|
||||
}
|
||||
49
vendor/sigs.k8s.io/kustomize/kyaml/yaml/doc.go
generated
vendored
Normal file
49
vendor/sigs.k8s.io/kustomize/kyaml/yaml/doc.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package yaml contains libraries for manipulating individual Kubernetes Resource
|
||||
// Configuration as yaml, keeping yaml structure and comments.
|
||||
//
|
||||
// Parsing Resources
|
||||
//
|
||||
// Typically Resources will be initialized as collections through the kio package libraries.
|
||||
// However it is possible to directly initialize Resources using Parse.
|
||||
// resource, err := yaml.Parse("apiVersion: apps/v1\nkind: Deployment")
|
||||
//
|
||||
// Processing Resources
|
||||
//
|
||||
// Individual Resources are manipulated using the Pipe and PipeE to apply Filter functions
|
||||
// to transform the Resource data.
|
||||
// err := resource.PipeE(yaml.SetAnnotation("key", "value"))
|
||||
//
|
||||
// If multiple Filter functions are provided to Pipe or PipeE, each function is applied to
|
||||
// the result of the last function -- e.g. yaml.Lookup(...), yaml.SetField(...)
|
||||
//
|
||||
// Field values may also be retrieved using Pipe.
|
||||
// annotationValue, err := resource.Pipe(yaml.GetAnnotation("key"))
|
||||
//
|
||||
// See http://www.linfo.org/filters.html for a definition of filters.
|
||||
//
|
||||
// Common Filters
|
||||
//
|
||||
// There are a number of standard filter functions provided by the yaml package.
|
||||
//
|
||||
// Working with annotations:
|
||||
// [AnnotationSetter{}, AnnotationGetter{}, AnnotationClearer{}]
|
||||
//
|
||||
// Working with fields by path:
|
||||
// [PathMatcher{}, PathGetter{}]
|
||||
//
|
||||
// Working with individual fields on Maps and Objects:
|
||||
// [FieldMatcher{}, FieldSetter{}, FieldGetter{}]
|
||||
//
|
||||
// Working with individual elements in Sequences:
|
||||
// [ElementAppender{}, ElementSetter{}, ElementMatcher{}]
|
||||
//
|
||||
// Writing Filters
|
||||
//
|
||||
// Users may implement their own filter functions. When doing so, can be necessary to work with
|
||||
// the RNode directly rather than through Pipe. RNode provides a number of functions for doing
|
||||
// so. See:
|
||||
// [GetMeta(), Fields(), Elements(), String()]
|
||||
package yaml
|
||||
146
vendor/sigs.k8s.io/kustomize/kyaml/yaml/filters.go
generated
vendored
Normal file
146
vendor/sigs.k8s.io/kustomize/kyaml/yaml/filters.go
generated
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Filters is the list of serializable Pipeline Filters
|
||||
var Filters = map[string]func() Filter{
|
||||
"AnnotationClearer": func() Filter { return &AnnotationClearer{} },
|
||||
"AnnotationGetter": func() Filter { return &AnnotationGetter{} },
|
||||
"AnnotationSetter": func() Filter { return &AnnotationSetter{} },
|
||||
"LabelSetter": func() Filter { return &LabelSetter{} },
|
||||
"ElementAppender": func() Filter { return &ElementAppender{} },
|
||||
"ElementMatcher": func() Filter { return &ElementMatcher{} },
|
||||
"FieldClearer": func() Filter { return &FieldClearer{} },
|
||||
"FilterMatcher": func() Filter { return &FilterMatcher{} },
|
||||
"FieldMatcher": func() Filter { return &FieldMatcher{} },
|
||||
"FieldSetter": func() Filter { return &FieldSetter{} },
|
||||
"PathGetter": func() Filter { return &PathGetter{} },
|
||||
"PathMatcher": func() Filter { return &PathMatcher{} },
|
||||
"Parser": func() Filter { return &Parser{} },
|
||||
"PrefixSetter": func() Filter { return &PrefixSetter{} },
|
||||
"ValueReplacer": func() Filter { return &ValueReplacer{} },
|
||||
"SuffixSetter": func() Filter { return &SuffixSetter{} },
|
||||
"TeePiper": func() Filter { return &TeePiper{} },
|
||||
}
|
||||
|
||||
// YFilter wraps the Filter interface so the filter can be represented as
|
||||
// data and can be unmarshalled into a struct from a yaml config file.
|
||||
// This allows Pipelines to be expressed as data rather than code.
|
||||
type YFilter struct {
|
||||
Filter
|
||||
}
|
||||
|
||||
func (y YFilter) MarshalYAML() (interface{}, error) {
|
||||
return y.Filter, nil
|
||||
}
|
||||
|
||||
func (y *YFilter) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
meta := &ResourceMeta{}
|
||||
if err := unmarshal(meta); err != nil {
|
||||
return err
|
||||
}
|
||||
filter, found := Filters[meta.Kind]
|
||||
if !found {
|
||||
var knownFilters []string
|
||||
for k := range Filters {
|
||||
knownFilters = append(knownFilters, k)
|
||||
}
|
||||
sort.Strings(knownFilters)
|
||||
return fmt.Errorf("unsupported Filter Kind %s: may be one of: [%s]",
|
||||
meta.Kind, strings.Join(knownFilters, ","))
|
||||
}
|
||||
y.Filter = filter()
|
||||
|
||||
if err := unmarshal(y.Filter); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type YFilters []YFilter
|
||||
|
||||
func (y YFilters) Filters() []Filter {
|
||||
var f []Filter
|
||||
for i := range y {
|
||||
f = append(f, y[i].Filter)
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
type FilterMatcher struct {
|
||||
Kind string `yaml:"kind"`
|
||||
|
||||
// Filters are the set of Filters run by TeePiper.
|
||||
Filters YFilters `yaml:"pipeline,omitempty"`
|
||||
}
|
||||
|
||||
func (t FilterMatcher) Filter(rn *RNode) (*RNode, error) {
|
||||
v, err := rn.Pipe(t.Filters.Filters()...)
|
||||
if v == nil || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// return the original input if the pipeline resolves to true
|
||||
return rn, err
|
||||
}
|
||||
|
||||
type ValueReplacer struct {
|
||||
Kind string `yaml:"kind"`
|
||||
|
||||
StringMatch string `yaml:"stringMatch"`
|
||||
RegexMatch string `yaml:"regexMatch"`
|
||||
Replace string `yaml:"replace"`
|
||||
Count int `yaml:"count"`
|
||||
}
|
||||
|
||||
func (s ValueReplacer) Filter(object *RNode) (*RNode, error) {
|
||||
if s.Count == 0 {
|
||||
s.Count = -1
|
||||
}
|
||||
switch {
|
||||
case s.StringMatch != "":
|
||||
object.value.Value = strings.Replace(object.value.Value, s.StringMatch, s.Replace, s.Count)
|
||||
case s.RegexMatch != "":
|
||||
r, err := regexp.Compile(s.RegexMatch)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ValueReplacer RegexMatch does not compile: %v", err)
|
||||
}
|
||||
object.value.Value = r.ReplaceAllString(object.value.Value, s.Replace)
|
||||
default:
|
||||
return nil, fmt.Errorf("ValueReplacer missing StringMatch and RegexMatch")
|
||||
}
|
||||
return object, nil
|
||||
}
|
||||
|
||||
type PrefixSetter struct {
|
||||
Kind string `yaml:"kind"`
|
||||
|
||||
Value string `yaml:"value"`
|
||||
}
|
||||
|
||||
func (s PrefixSetter) Filter(object *RNode) (*RNode, error) {
|
||||
if !strings.HasPrefix(object.value.Value, s.Value) {
|
||||
object.value.Value = s.Value + object.value.Value
|
||||
}
|
||||
return object, nil
|
||||
}
|
||||
|
||||
type SuffixSetter struct {
|
||||
Kind string `yaml:"kind"`
|
||||
|
||||
Value string `yaml:"value"`
|
||||
}
|
||||
|
||||
func (s SuffixSetter) Filter(object *RNode) (*RNode, error) {
|
||||
if !strings.HasSuffix(object.value.Value, s.Value) {
|
||||
object.value.Value += s.Value
|
||||
}
|
||||
return object, nil
|
||||
}
|
||||
769
vendor/sigs.k8s.io/kustomize/kyaml/yaml/fns.go
generated
vendored
Normal file
769
vendor/sigs.k8s.io/kustomize/kyaml/yaml/fns.go
generated
vendored
Normal file
@@ -0,0 +1,769 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"gopkg.in/yaml.v3"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
)
|
||||
|
||||
// Append creates an ElementAppender
|
||||
func Append(elements ...*yaml.Node) ElementAppender {
|
||||
return ElementAppender{Elements: elements}
|
||||
}
|
||||
|
||||
// ElementAppender adds all element to a SequenceNode's Content.
|
||||
// Returns Elements[0] if len(Elements) == 1, otherwise returns nil.
|
||||
type ElementAppender struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
|
||||
// Elem is the value to append.
|
||||
Elements []*yaml.Node `yaml:"elements,omitempty"`
|
||||
}
|
||||
|
||||
func (a ElementAppender) Filter(rn *RNode) (*RNode, error) {
|
||||
if err := ErrorIfInvalid(rn, yaml.SequenceNode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := range a.Elements {
|
||||
rn.YNode().Content = append(rn.Content(), a.Elements[i])
|
||||
}
|
||||
if len(a.Elements) == 1 {
|
||||
return NewRNode(a.Elements[0]), nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ElementSetter sets the value for an Element in an associative list.
|
||||
// ElementSetter will append, replace or delete an element in an associative list.
|
||||
// To append, user a key-value pair that doesn't exist in the sequence. this
|
||||
// behavior is intended to handle the case that not matching element found. It's
|
||||
// not designed for this purpose. To append an element, please use ElementAppender.
|
||||
// To replace, set the key-value pair and a non-nil Element.
|
||||
// To delete, set the key-value pair and leave the Element as nil.
|
||||
// Every key must have a corresponding value.
|
||||
type ElementSetter struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
|
||||
// Element is the new value to set -- remove the existing element if nil
|
||||
Element *Node
|
||||
|
||||
// Key is a list of fields on the elements. It is used to find matching elements to
|
||||
// update / delete
|
||||
Keys []string
|
||||
|
||||
// Value is a list of field values on the elements corresponding to the keys. It is
|
||||
// used to find matching elements to update / delete.
|
||||
Values []string
|
||||
}
|
||||
|
||||
// isMappingNode returns whether node is a mapping node
|
||||
func (e ElementSetter) isMappingNode(node *RNode) bool {
|
||||
return ErrorIfInvalid(node, yaml.MappingNode) == nil
|
||||
}
|
||||
|
||||
// isMappingSetter returns is this setter intended to set a mapping node
|
||||
func (e ElementSetter) isMappingSetter() bool {
|
||||
return len(e.Keys) > 0 && e.Keys[0] != "" &&
|
||||
len(e.Values) > 0 && e.Values[0] != ""
|
||||
}
|
||||
|
||||
func (e ElementSetter) Filter(rn *RNode) (*RNode, error) {
|
||||
if len(e.Keys) == 0 {
|
||||
e.Keys = append(e.Keys, "")
|
||||
}
|
||||
|
||||
if err := ErrorIfInvalid(rn, SequenceNode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// build the new Content slice
|
||||
var newContent []*yaml.Node
|
||||
matchingElementFound := false
|
||||
for i := range rn.YNode().Content {
|
||||
elem := rn.Content()[i]
|
||||
newNode := NewRNode(elem)
|
||||
|
||||
// empty elements are not valid -- they at least need an associative key
|
||||
if IsMissingOrNull(newNode) || IsEmptyMap(newNode) {
|
||||
continue
|
||||
}
|
||||
// keep non-mapping node in the Content when we want to match a mapping.
|
||||
if !e.isMappingNode(newNode) && e.isMappingSetter() {
|
||||
newContent = append(newContent, elem)
|
||||
continue
|
||||
}
|
||||
|
||||
// check if this is the element we are matching
|
||||
var val *RNode
|
||||
var err error
|
||||
found := true
|
||||
for j := range e.Keys {
|
||||
if j < len(e.Values) {
|
||||
val, err = newNode.Pipe(FieldMatcher{Name: e.Keys[j], StringValue: e.Values[j]})
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if val == nil {
|
||||
found = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
// not the element we are looking for, keep it in the Content
|
||||
if len(e.Values) > 0 {
|
||||
newContent = append(newContent, elem)
|
||||
}
|
||||
continue
|
||||
}
|
||||
matchingElementFound = true
|
||||
|
||||
// deletion operation -- remove the element from the new Content
|
||||
if e.Element == nil {
|
||||
continue
|
||||
}
|
||||
// replace operation -- replace the element in the Content
|
||||
newContent = append(newContent, e.Element)
|
||||
}
|
||||
rn.YNode().Content = newContent
|
||||
|
||||
// deletion operation -- return nil
|
||||
if IsMissingOrNull(NewRNode(e.Element)) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// append operation -- add the element to the Content
|
||||
if !matchingElementFound {
|
||||
rn.YNode().Content = append(rn.YNode().Content, e.Element)
|
||||
}
|
||||
|
||||
return NewRNode(e.Element), nil
|
||||
}
|
||||
|
||||
// GetElementByIndex will return a Filter which can be applied to a sequence
|
||||
// node to get the element specified by the index
|
||||
func GetElementByIndex(index int) ElementIndexer {
|
||||
return ElementIndexer{Index: index}
|
||||
}
|
||||
|
||||
// ElementIndexer picks the element with a specified index. Index starts from
|
||||
// 0 to len(list) - 1. a hyphen ("-") means the last index.
|
||||
type ElementIndexer struct {
|
||||
Index int
|
||||
}
|
||||
|
||||
// Filter implements Filter
|
||||
func (i ElementIndexer) Filter(rn *RNode) (*RNode, error) {
|
||||
// rn.Elements will return error if rn is not a sequence node.
|
||||
elems, err := rn.Elements()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if i.Index < 0 {
|
||||
return elems[len(elems)-1], nil
|
||||
}
|
||||
if i.Index >= len(elems) {
|
||||
return nil, nil
|
||||
}
|
||||
return elems[i.Index], nil
|
||||
}
|
||||
|
||||
// Clear returns a FieldClearer
|
||||
func Clear(name string) FieldClearer {
|
||||
return FieldClearer{Name: name}
|
||||
}
|
||||
|
||||
// FieldClearer removes the field or map key.
|
||||
// Returns a RNode with the removed field or map entry.
|
||||
type FieldClearer struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
|
||||
// Name is the name of the field or key in the map.
|
||||
Name string `yaml:"name,omitempty"`
|
||||
|
||||
IfEmpty bool `yaml:"ifEmpty,omitempty"`
|
||||
}
|
||||
|
||||
func (c FieldClearer) Filter(rn *RNode) (*RNode, error) {
|
||||
if err := ErrorIfInvalid(rn, yaml.MappingNode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := 0; i < len(rn.Content()); i += 2 {
|
||||
// if name matches, remove these 2 elements from the list because
|
||||
// they are treated as a fieldName/fieldValue pair.
|
||||
if rn.Content()[i].Value == c.Name {
|
||||
if c.IfEmpty {
|
||||
if len(rn.Content()[i+1].Content) > 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// save the item we are about to remove
|
||||
removed := NewRNode(rn.Content()[i+1])
|
||||
if len(rn.YNode().Content) > i+2 {
|
||||
l := len(rn.YNode().Content)
|
||||
// remove from the middle of the list
|
||||
rn.YNode().Content = rn.Content()[:i]
|
||||
rn.YNode().Content = append(
|
||||
rn.YNode().Content,
|
||||
rn.Content()[i+2:l]...)
|
||||
} else {
|
||||
// remove from the end of the list
|
||||
rn.YNode().Content = rn.Content()[:i]
|
||||
}
|
||||
|
||||
// return the removed field name and value
|
||||
return removed, nil
|
||||
}
|
||||
}
|
||||
// nothing removed
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func MatchElement(field, value string) ElementMatcher {
|
||||
return ElementMatcher{Keys: []string{field}, Values: []string{value}}
|
||||
}
|
||||
|
||||
func MatchElementList(keys []string, values []string) ElementMatcher {
|
||||
return ElementMatcher{Keys: keys, Values: values}
|
||||
}
|
||||
|
||||
func GetElementByKey(key string) ElementMatcher {
|
||||
return ElementMatcher{Keys: []string{key}, MatchAnyValue: true}
|
||||
}
|
||||
|
||||
// ElementMatcher returns the first element from a Sequence matching the
|
||||
// specified key-value pairs. If there's no match, and no configuration error,
|
||||
// the matcher returns nil, nil.
|
||||
type ElementMatcher struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
|
||||
// Keys are the list of fields upon which to match this element.
|
||||
Keys []string
|
||||
|
||||
// Values are the list of values upon which to match this element.
|
||||
Values []string
|
||||
|
||||
// Create will create the Element if it is not found
|
||||
Create *RNode `yaml:"create,omitempty"`
|
||||
|
||||
// MatchAnyValue indicates that matcher should only consider the key and ignore
|
||||
// the actual value in the list. Values must be empty when MatchAnyValue is
|
||||
// set to true.
|
||||
MatchAnyValue bool `yaml:"noValue,omitempty"`
|
||||
}
|
||||
|
||||
func (e ElementMatcher) Filter(rn *RNode) (*RNode, error) {
|
||||
if len(e.Keys) == 0 {
|
||||
e.Keys = append(e.Keys, "")
|
||||
}
|
||||
if len(e.Values) == 0 {
|
||||
e.Values = append(e.Values, "")
|
||||
}
|
||||
|
||||
if err := ErrorIfInvalid(rn, yaml.SequenceNode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if e.MatchAnyValue && len(e.Values) != 0 && e.Values[0] != "" {
|
||||
return nil, fmt.Errorf("Values must be empty when MatchAnyValue is set to true")
|
||||
}
|
||||
|
||||
// SequenceNode Content is a slice of ScalarNodes. Each ScalarNode has a
|
||||
// YNode containing the primitive data.
|
||||
if len(e.Keys) == 0 || len(e.Keys[0]) == 0 {
|
||||
for i := range rn.Content() {
|
||||
if rn.Content()[i].Value == e.Values[0] {
|
||||
return &RNode{value: rn.Content()[i]}, nil
|
||||
}
|
||||
}
|
||||
if e.Create != nil {
|
||||
return rn.Pipe(Append(e.Create.YNode()))
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// SequenceNode Content is a slice of MappingNodes. Each MappingNode has Content
|
||||
// with a slice of key-value pairs containing the fields.
|
||||
for i := range rn.Content() {
|
||||
// cast the entry to a RNode so we can operate on it
|
||||
elem := NewRNode(rn.Content()[i])
|
||||
var field *RNode
|
||||
var err error
|
||||
|
||||
// only check mapping node
|
||||
if err = ErrorIfInvalid(elem, yaml.MappingNode); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if !e.MatchAnyValue && len(e.Keys) != len(e.Values) {
|
||||
return nil, fmt.Errorf("length of keys must equal length of values when MatchAnyValue is false")
|
||||
}
|
||||
|
||||
matchesElement := true
|
||||
for i := range e.Keys {
|
||||
if e.MatchAnyValue {
|
||||
field, err = elem.Pipe(Get(e.Keys[i]))
|
||||
} else {
|
||||
field, err = elem.Pipe(MatchField(e.Keys[i], e.Values[i]))
|
||||
}
|
||||
if !IsFoundOrError(field, err) {
|
||||
// this is not the element we are looking for
|
||||
matchesElement = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if matchesElement {
|
||||
return elem, err
|
||||
}
|
||||
}
|
||||
|
||||
// create the element
|
||||
if e.Create != nil {
|
||||
return rn.Pipe(Append(e.Create.YNode()))
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func Get(name string) FieldMatcher {
|
||||
return FieldMatcher{Name: name}
|
||||
}
|
||||
|
||||
func MatchField(name, value string) FieldMatcher {
|
||||
return FieldMatcher{Name: name, Value: NewScalarRNode(value)}
|
||||
}
|
||||
|
||||
func Match(value string) FieldMatcher {
|
||||
return FieldMatcher{Value: NewScalarRNode(value)}
|
||||
}
|
||||
|
||||
// FieldMatcher returns the value of a named field or map entry.
|
||||
type FieldMatcher struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
|
||||
// Name of the field to return
|
||||
Name string `yaml:"name,omitempty"`
|
||||
|
||||
// YNode of the field to return.
|
||||
// Optional. Will only need to match field name if unset.
|
||||
Value *RNode `yaml:"value,omitempty"`
|
||||
|
||||
StringValue string `yaml:"stringValue,omitempty"`
|
||||
|
||||
StringRegexValue string `yaml:"stringRegexValue,omitempty"`
|
||||
|
||||
// Create will cause the field to be created with this value
|
||||
// if it is set.
|
||||
Create *RNode `yaml:"create,omitempty"`
|
||||
}
|
||||
|
||||
func (f FieldMatcher) Filter(rn *RNode) (*RNode, error) {
|
||||
if f.StringValue != "" && f.Value == nil {
|
||||
f.Value = NewScalarRNode(f.StringValue)
|
||||
}
|
||||
|
||||
// never match nil or null fields
|
||||
if IsMissingOrNull(rn) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if f.Name == "" {
|
||||
if err := ErrorIfInvalid(rn, yaml.ScalarNode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch {
|
||||
case f.StringRegexValue != "":
|
||||
// TODO(pwittrock): pre-compile this when unmarshalling and cache to a field
|
||||
rg, err := regexp.Compile(f.StringRegexValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if match := rg.MatchString(rn.value.Value); match {
|
||||
return rn, nil
|
||||
}
|
||||
return nil, nil
|
||||
case GetValue(rn) == GetValue(f.Value):
|
||||
return rn, nil
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
if err := ErrorIfInvalid(rn, yaml.MappingNode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := 0; i < len(rn.Content()); i = IncrementFieldIndex(i) {
|
||||
isMatchingField := rn.Content()[i].Value == f.Name
|
||||
if isMatchingField {
|
||||
requireMatchFieldValue := f.Value != nil
|
||||
if !requireMatchFieldValue || rn.Content()[i+1].Value == f.Value.YNode().Value {
|
||||
return NewRNode(rn.Content()[i+1]), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if f.Create != nil {
|
||||
return rn.Pipe(SetField(f.Name, f.Create))
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Lookup returns a PathGetter to lookup a field by its path.
|
||||
func Lookup(path ...string) PathGetter {
|
||||
return PathGetter{Path: path}
|
||||
}
|
||||
|
||||
// Lookup returns a PathGetter to lookup a field by its path and create it if it doesn't already
|
||||
// exist.
|
||||
func LookupCreate(kind yaml.Kind, path ...string) PathGetter {
|
||||
return PathGetter{Path: path, Create: kind}
|
||||
}
|
||||
|
||||
// PathGetter returns the RNode under Path.
|
||||
type PathGetter struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
|
||||
// Path is a slice of parts leading to the RNode to lookup.
|
||||
// Each path part may be one of:
|
||||
// * FieldMatcher -- e.g. "spec"
|
||||
// * Map Key -- e.g. "app.k8s.io/version"
|
||||
// * List Entry -- e.g. "[name=nginx]" or "[=-jar]" or "0" or "-"
|
||||
//
|
||||
// Map Keys and Fields are equivalent.
|
||||
// See FieldMatcher for more on Fields and Map Keys.
|
||||
//
|
||||
// List Entries can be specified as map entry to match [fieldName=fieldValue]
|
||||
// or a positional index like 0 to get the element. - (unquoted hyphen) is
|
||||
// special and means the last element.
|
||||
//
|
||||
// See Elem for more on List Entries.
|
||||
//
|
||||
// Examples:
|
||||
// * spec.template.spec.container with matching name: [name=nginx]
|
||||
// * spec.template.spec.container.argument matching a value: [=-jar]
|
||||
Path []string `yaml:"path,omitempty"`
|
||||
|
||||
// Create will cause missing path parts to be created as they are walked.
|
||||
//
|
||||
// * The leaf Node (final path) will be created with a Kind matching Create
|
||||
// * Intermediary Nodes will be created as either a MappingNodes or
|
||||
// SequenceNodes as appropriate for each's Path location.
|
||||
// * If a list item is specified by a index (an offset or "-"), this item will
|
||||
// not be created even Create is set.
|
||||
Create yaml.Kind `yaml:"create,omitempty"`
|
||||
|
||||
// Style is the style to apply to created value Nodes.
|
||||
// Created key Nodes keep an unspecified Style.
|
||||
Style yaml.Style `yaml:"style,omitempty"`
|
||||
}
|
||||
|
||||
func (l PathGetter) Filter(rn *RNode) (*RNode, error) {
|
||||
var err error
|
||||
fieldPath := append([]string{}, rn.FieldPath()...)
|
||||
match := rn
|
||||
|
||||
// iterate over path until encountering an error or missing value
|
||||
l.Path = cleanPath(l.Path)
|
||||
for i := range l.Path {
|
||||
var part, nextPart string
|
||||
part = l.Path[i]
|
||||
if len(l.Path) > i+1 {
|
||||
nextPart = l.Path[i+1]
|
||||
}
|
||||
var fltr Filter
|
||||
fltr, err = l.getFilter(part, nextPart, &fieldPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
match, err = match.Pipe(fltr)
|
||||
if IsMissingOrError(match, err) {
|
||||
return nil, err
|
||||
}
|
||||
match.AppendToFieldPath(fieldPath...)
|
||||
}
|
||||
return match, nil
|
||||
}
|
||||
|
||||
func (l PathGetter) getFilter(part, nextPart string, fieldPath *[]string) (Filter, error) {
|
||||
idx, err := strconv.Atoi(part)
|
||||
switch {
|
||||
case err == nil:
|
||||
// part is a number
|
||||
if idx < 0 {
|
||||
return nil, fmt.Errorf("array index %d cannot be negative", idx)
|
||||
}
|
||||
return GetElementByIndex(idx), nil
|
||||
case part == "-":
|
||||
// part is a hyphen
|
||||
return GetElementByIndex(-1), nil
|
||||
case IsListIndex(part):
|
||||
// part is surrounded by brackets
|
||||
return l.elemFilter(part)
|
||||
default:
|
||||
// mapping node
|
||||
*fieldPath = append(*fieldPath, part)
|
||||
return l.fieldFilter(part, l.getKind(nextPart))
|
||||
}
|
||||
}
|
||||
|
||||
func (l PathGetter) elemFilter(part string) (Filter, error) {
|
||||
var match *RNode
|
||||
name, value, err := SplitIndexNameValue(part)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err)
|
||||
}
|
||||
if !IsCreate(l.Create) {
|
||||
return MatchElement(name, value), nil
|
||||
}
|
||||
|
||||
var elem *RNode
|
||||
primitiveElement := len(name) == 0
|
||||
if primitiveElement {
|
||||
// append a ScalarNode
|
||||
elem = NewScalarRNode(value)
|
||||
elem.YNode().Style = l.Style
|
||||
match = elem
|
||||
} else {
|
||||
// append a MappingNode
|
||||
match = NewRNode(&yaml.Node{Kind: yaml.ScalarNode, Value: value, Style: l.Style})
|
||||
elem = NewRNode(&yaml.Node{
|
||||
Kind: yaml.MappingNode,
|
||||
Content: []*yaml.Node{{Kind: yaml.ScalarNode, Value: name}, match.YNode()},
|
||||
Style: l.Style,
|
||||
})
|
||||
}
|
||||
// Append the Node
|
||||
return ElementMatcher{Keys: []string{name}, Values: []string{value}, Create: elem}, nil
|
||||
}
|
||||
|
||||
func (l PathGetter) fieldFilter(
|
||||
name string, kind yaml.Kind) (Filter, error) {
|
||||
if !IsCreate(l.Create) {
|
||||
return Get(name), nil
|
||||
}
|
||||
return FieldMatcher{Name: name, Create: &RNode{value: &yaml.Node{Kind: kind, Style: l.Style}}}, nil
|
||||
}
|
||||
|
||||
func (l PathGetter) getKind(nextPart string) yaml.Kind {
|
||||
if IsListIndex(nextPart) {
|
||||
// if nextPart is of the form [a=b], then it is an index into a Sequence
|
||||
// so the current part must be a SequenceNode
|
||||
return yaml.SequenceNode
|
||||
}
|
||||
if nextPart == "" {
|
||||
// final name in the path, use the l.Create defined Kind
|
||||
return l.Create
|
||||
}
|
||||
|
||||
// non-sequence intermediate Node
|
||||
return yaml.MappingNode
|
||||
}
|
||||
|
||||
func SetField(name string, value *RNode) FieldSetter {
|
||||
return FieldSetter{Name: name, Value: value}
|
||||
}
|
||||
|
||||
func Set(value *RNode) FieldSetter {
|
||||
return FieldSetter{Value: value}
|
||||
}
|
||||
|
||||
// FieldSetter sets a field or map entry to a value.
|
||||
type FieldSetter struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
|
||||
// Name is the name of the field or key to lookup in a MappingNode.
|
||||
// If Name is unspecified, and the input is a ScalarNode, FieldSetter will set the
|
||||
// value on the ScalarNode.
|
||||
Name string `yaml:"name,omitempty"`
|
||||
|
||||
// Comments for the field
|
||||
Comments Comments `yaml:"comments,omitempty"`
|
||||
|
||||
// Value is the value to set.
|
||||
// Optional if Kind is set.
|
||||
Value *RNode `yaml:"value,omitempty"`
|
||||
|
||||
StringValue string `yaml:"stringValue,omitempty"`
|
||||
|
||||
// OverrideStyle can be set to override the style of the existing node
|
||||
// when setting it. Otherwise, if an existing node is found, the style is
|
||||
// retained.
|
||||
OverrideStyle bool `yaml:"overrideStyle,omitempty"`
|
||||
}
|
||||
|
||||
func (s FieldSetter) Filter(rn *RNode) (*RNode, error) {
|
||||
if s.StringValue != "" && s.Value == nil {
|
||||
s.Value = NewScalarRNode(s.StringValue)
|
||||
}
|
||||
|
||||
if s.Name == "" {
|
||||
if err := ErrorIfInvalid(rn, yaml.ScalarNode); err != nil {
|
||||
return rn, err
|
||||
}
|
||||
if IsMissingOrNull(s.Value) {
|
||||
return rn, nil
|
||||
}
|
||||
// only apply the style if there is not an existing style
|
||||
// or we want to override it
|
||||
if !s.OverrideStyle || s.Value.YNode().Style == 0 {
|
||||
// keep the original style if it exists
|
||||
s.Value.YNode().Style = rn.YNode().Style
|
||||
}
|
||||
rn.SetYNode(s.Value.YNode())
|
||||
return rn, nil
|
||||
}
|
||||
|
||||
// Clear the field if it is empty, or explicitly null
|
||||
if s.Value == nil || s.Value.IsTaggedNull() {
|
||||
return rn.Pipe(Clear(s.Name))
|
||||
}
|
||||
|
||||
field, err := rn.Pipe(FieldMatcher{Name: s.Name})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if field != nil {
|
||||
// only apply the style if there is not an existing style
|
||||
// or we want to override it
|
||||
if !s.OverrideStyle || field.YNode().Style == 0 {
|
||||
// keep the original style if it exists
|
||||
s.Value.YNode().Style = field.YNode().Style
|
||||
}
|
||||
// need to def ref the Node since field is ephemeral
|
||||
field.SetYNode(s.Value.YNode())
|
||||
return field, nil
|
||||
}
|
||||
|
||||
// create the field
|
||||
rn.YNode().Content = append(
|
||||
rn.YNode().Content,
|
||||
&yaml.Node{
|
||||
Kind: yaml.ScalarNode,
|
||||
Value: s.Name,
|
||||
HeadComment: s.Comments.HeadComment,
|
||||
LineComment: s.Comments.LineComment,
|
||||
FootComment: s.Comments.FootComment,
|
||||
},
|
||||
s.Value.YNode())
|
||||
return s.Value, nil
|
||||
}
|
||||
|
||||
// Tee calls the provided Filters, and returns its argument rather than the result
|
||||
// of the filters.
|
||||
// May be used to fork sub-filters from a call.
|
||||
// e.g. locate field, set value; locate another field, set another value
|
||||
func Tee(filters ...Filter) Filter {
|
||||
return TeePiper{Filters: filters}
|
||||
}
|
||||
|
||||
// TeePiper Calls a slice of Filters and returns its input.
|
||||
// May be used to fork sub-filters from a call.
|
||||
// e.g. locate field, set value; locate another field, set another value
|
||||
type TeePiper struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
|
||||
// Filters are the set of Filters run by TeePiper.
|
||||
Filters []Filter `yaml:"filters,omitempty"`
|
||||
}
|
||||
|
||||
func (t TeePiper) Filter(rn *RNode) (*RNode, error) {
|
||||
_, err := rn.Pipe(t.Filters...)
|
||||
return rn, err
|
||||
}
|
||||
|
||||
// IsCreate returns true if kind is specified
|
||||
func IsCreate(kind yaml.Kind) bool {
|
||||
return kind != 0
|
||||
}
|
||||
|
||||
// IsMissingOrError returns true if rn is NOT found or err is non-nil
|
||||
func IsMissingOrError(rn *RNode, err error) bool {
|
||||
return rn == nil || err != nil
|
||||
}
|
||||
|
||||
// IsFoundOrError returns true if rn is found or err is non-nil
|
||||
func IsFoundOrError(rn *RNode, err error) bool {
|
||||
return rn != nil || err != nil
|
||||
}
|
||||
|
||||
func ErrorIfAnyInvalidAndNonNull(kind yaml.Kind, rn ...*RNode) error {
|
||||
for i := range rn {
|
||||
if IsMissingOrNull(rn[i]) {
|
||||
continue
|
||||
}
|
||||
if err := ErrorIfInvalid(rn[i], kind); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var nodeTypeIndex = map[yaml.Kind]string{
|
||||
yaml.SequenceNode: "SequenceNode",
|
||||
yaml.MappingNode: "MappingNode",
|
||||
yaml.ScalarNode: "ScalarNode",
|
||||
yaml.DocumentNode: "DocumentNode",
|
||||
yaml.AliasNode: "AliasNode",
|
||||
}
|
||||
|
||||
func ErrorIfInvalid(rn *RNode, kind yaml.Kind) error {
|
||||
if IsMissingOrNull(rn) {
|
||||
// node has no type, pass validation
|
||||
return nil
|
||||
}
|
||||
|
||||
if rn.YNode().Kind != kind {
|
||||
s, _ := rn.String()
|
||||
return errors.Errorf(
|
||||
"wrong Node Kind for %s expected: %v was %v: value: {%s}",
|
||||
strings.Join(rn.FieldPath(), "."),
|
||||
nodeTypeIndex[kind], nodeTypeIndex[rn.YNode().Kind], strings.TrimSpace(s))
|
||||
}
|
||||
|
||||
if kind == yaml.MappingNode {
|
||||
if len(rn.YNode().Content)%2 != 0 {
|
||||
return errors.Errorf(
|
||||
"yaml MappingNodes must have even length contents: %v", spew.Sdump(rn))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsListIndex returns true if p is an index into a Val.
|
||||
// e.g. [fieldName=fieldValue]
|
||||
// e.g. [=primitiveValue]
|
||||
func IsListIndex(p string) bool {
|
||||
return strings.HasPrefix(p, "[") && strings.HasSuffix(p, "]")
|
||||
}
|
||||
|
||||
// SplitIndexNameValue splits a lookup part Val index into the field name
|
||||
// and field value to match.
|
||||
// e.g. splits [name=nginx] into (name, nginx)
|
||||
// e.g. splits [=-jar] into ("", -jar)
|
||||
func SplitIndexNameValue(p string) (string, string, error) {
|
||||
elem := strings.TrimSuffix(p, "]")
|
||||
elem = strings.TrimPrefix(elem, "[")
|
||||
parts := strings.SplitN(elem, "=", 2)
|
||||
if len(parts) == 1 {
|
||||
return "", "", fmt.Errorf("list path element must contain fieldName=fieldValue for element to match")
|
||||
}
|
||||
return parts[0], parts[1], nil
|
||||
}
|
||||
|
||||
// IncrementFieldIndex increments i to point to the next field name element in
|
||||
// a slice of Contents.
|
||||
func IncrementFieldIndex(i int) int {
|
||||
return i + 2
|
||||
}
|
||||
43
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/labels/copied.deepcopy.go
generated
vendored
Normal file
43
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/labels/copied.deepcopy.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
// Code generated by k8scopy from k8s.io/apimachinery@v0.19.8; DO NOT EDIT.
|
||||
// File content copied from k8s.io/apimachinery@v0.19.8/pkg/labels/zz_generated.deepcopy.go
|
||||
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package labels
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Requirement) DeepCopyInto(out *Requirement) {
|
||||
*out = *in
|
||||
if in.strValues != nil {
|
||||
in, out := &in.strValues, &out.strValues
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Requirement.
|
||||
func (in *Requirement) DeepCopy() *Requirement {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Requirement)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
192
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/labels/labels.go
generated
vendored
Normal file
192
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/labels/labels.go
generated
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
// Code generated by k8scopy from k8s.io/apimachinery@v0.19.8; DO NOT EDIT.
|
||||
// File content copied from k8s.io/apimachinery@v0.19.8/pkg/labels/labels.go
|
||||
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package labels
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Labels allows you to present labels independently from their storage.
|
||||
type Labels interface {
|
||||
// Has returns whether the provided label exists.
|
||||
Has(label string) (exists bool)
|
||||
|
||||
// Get returns the value for the provided label.
|
||||
Get(label string) (value string)
|
||||
}
|
||||
|
||||
// Set is a map of label:value. It implements Labels.
|
||||
type Set map[string]string
|
||||
|
||||
// String returns all labels listed as a human readable string.
|
||||
// Conveniently, exactly the format that ParseSelector takes.
|
||||
func (ls Set) String() string {
|
||||
selector := make([]string, 0, len(ls))
|
||||
for key, value := range ls {
|
||||
selector = append(selector, key+"="+value)
|
||||
}
|
||||
// Sort for determinism.
|
||||
sort.StringSlice(selector).Sort()
|
||||
return strings.Join(selector, ",")
|
||||
}
|
||||
|
||||
// Has returns whether the provided label exists in the map.
|
||||
func (ls Set) Has(label string) bool {
|
||||
_, exists := ls[label]
|
||||
return exists
|
||||
}
|
||||
|
||||
// Get returns the value in the map for the provided label.
|
||||
func (ls Set) Get(label string) string {
|
||||
return ls[label]
|
||||
}
|
||||
|
||||
// AsSelector converts labels into a selectors. It does not
|
||||
// perform any validation, which means the server will reject
|
||||
// the request if the Set contains invalid values.
|
||||
func (ls Set) AsSelector() Selector {
|
||||
return SelectorFromSet(ls)
|
||||
}
|
||||
|
||||
// AsValidatedSelector converts labels into a selectors.
|
||||
// The Set is validated client-side, which allows to catch errors early.
|
||||
func (ls Set) AsValidatedSelector() (Selector, error) {
|
||||
return ValidatedSelectorFromSet(ls)
|
||||
}
|
||||
|
||||
// AsSelectorPreValidated converts labels into a selector, but
|
||||
// assumes that labels are already validated and thus doesn't
|
||||
// perform any validation.
|
||||
// According to our measurements this is significantly faster
|
||||
// in codepaths that matter at high scale.
|
||||
func (ls Set) AsSelectorPreValidated() Selector {
|
||||
return SelectorFromValidatedSet(ls)
|
||||
}
|
||||
|
||||
// FormatLabels convert label map into plain string
|
||||
func FormatLabels(labelMap map[string]string) string {
|
||||
l := Set(labelMap).String()
|
||||
if l == "" {
|
||||
l = "<none>"
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// Conflicts takes 2 maps and returns true if there a key match between
|
||||
// the maps but the value doesn't match, and returns false in other cases
|
||||
func Conflicts(labels1, labels2 Set) bool {
|
||||
small := labels1
|
||||
big := labels2
|
||||
if len(labels2) < len(labels1) {
|
||||
small = labels2
|
||||
big = labels1
|
||||
}
|
||||
|
||||
for k, v := range small {
|
||||
if val, match := big[k]; match {
|
||||
if val != v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Merge combines given maps, and does not check for any conflicts
|
||||
// between the maps. In case of conflicts, second map (labels2) wins
|
||||
func Merge(labels1, labels2 Set) Set {
|
||||
mergedMap := Set{}
|
||||
|
||||
for k, v := range labels1 {
|
||||
mergedMap[k] = v
|
||||
}
|
||||
for k, v := range labels2 {
|
||||
mergedMap[k] = v
|
||||
}
|
||||
return mergedMap
|
||||
}
|
||||
|
||||
// Equals returns true if the given maps are equal
|
||||
func Equals(labels1, labels2 Set) bool {
|
||||
if len(labels1) != len(labels2) {
|
||||
return false
|
||||
}
|
||||
|
||||
for k, v := range labels1 {
|
||||
value, ok := labels2[k]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if value != v {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// AreLabelsInWhiteList verifies if the provided label list
|
||||
// is in the provided whitelist and returns true, otherwise false.
|
||||
func AreLabelsInWhiteList(labels, whitelist Set) bool {
|
||||
if len(whitelist) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
for k, v := range labels {
|
||||
value, ok := whitelist[k]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if value != v {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ConvertSelectorToLabelsMap converts selector string to labels map
|
||||
// and validates keys and values
|
||||
func ConvertSelectorToLabelsMap(selector string) (Set, error) {
|
||||
labelsMap := Set{}
|
||||
|
||||
if len(selector) == 0 {
|
||||
return labelsMap, nil
|
||||
}
|
||||
|
||||
labels := strings.Split(selector, ",")
|
||||
for _, label := range labels {
|
||||
l := strings.Split(label, "=")
|
||||
if len(l) != 2 {
|
||||
return labelsMap, fmt.Errorf("invalid selector: %s", l)
|
||||
}
|
||||
key := strings.TrimSpace(l[0])
|
||||
if err := validateLabelKey(key); err != nil {
|
||||
return labelsMap, err
|
||||
}
|
||||
value := strings.TrimSpace(l[1])
|
||||
if err := validateLabelValue(key, value); err != nil {
|
||||
return labelsMap, err
|
||||
}
|
||||
labelsMap[key] = value
|
||||
}
|
||||
return labelsMap, nil
|
||||
}
|
||||
925
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/labels/selector.go
generated
vendored
Normal file
925
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/labels/selector.go
generated
vendored
Normal file
@@ -0,0 +1,925 @@
|
||||
// Code generated by k8scopy from k8s.io/apimachinery@v0.19.8; DO NOT EDIT.
|
||||
// File content copied from k8s.io/apimachinery@v0.19.8/pkg/labels/selector.go
|
||||
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package labels
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"log"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/selection"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/sets"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/validation"
|
||||
)
|
||||
|
||||
// Requirements is AND of all requirements.
|
||||
type Requirements []Requirement
|
||||
|
||||
// Selector represents a label selector.
|
||||
type Selector interface {
|
||||
// Matches returns true if this selector matches the given set of labels.
|
||||
Matches(Labels) bool
|
||||
|
||||
// Empty returns true if this selector does not restrict the selection space.
|
||||
Empty() bool
|
||||
|
||||
// String returns a human readable string that represents this selector.
|
||||
String() string
|
||||
|
||||
// Add adds requirements to the Selector
|
||||
Add(r ...Requirement) Selector
|
||||
|
||||
// Requirements converts this interface into Requirements to expose
|
||||
// more detailed selection information.
|
||||
// If there are querying parameters, it will return converted requirements and selectable=true.
|
||||
// If this selector doesn't want to select anything, it will return selectable=false.
|
||||
Requirements() (requirements Requirements, selectable bool)
|
||||
|
||||
// Make a deep copy of the selector.
|
||||
DeepCopySelector() Selector
|
||||
|
||||
// RequiresExactMatch allows a caller to introspect whether a given selector
|
||||
// requires a single specific label to be set, and if so returns the value it
|
||||
// requires.
|
||||
RequiresExactMatch(label string) (value string, found bool)
|
||||
}
|
||||
|
||||
// Everything returns a selector that matches all labels.
|
||||
func Everything() Selector {
|
||||
return internalSelector{}
|
||||
}
|
||||
|
||||
type nothingSelector struct{}
|
||||
|
||||
func (n nothingSelector) Matches(_ Labels) bool { return false }
|
||||
func (n nothingSelector) Empty() bool { return false }
|
||||
func (n nothingSelector) String() string { return "" }
|
||||
func (n nothingSelector) Add(_ ...Requirement) Selector { return n }
|
||||
func (n nothingSelector) Requirements() (Requirements, bool) { return nil, false }
|
||||
func (n nothingSelector) DeepCopySelector() Selector { return n }
|
||||
func (n nothingSelector) RequiresExactMatch(label string) (value string, found bool) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Nothing returns a selector that matches no labels
|
||||
func Nothing() Selector {
|
||||
return nothingSelector{}
|
||||
}
|
||||
|
||||
// NewSelector returns a nil selector
|
||||
func NewSelector() Selector {
|
||||
return internalSelector(nil)
|
||||
}
|
||||
|
||||
type internalSelector []Requirement
|
||||
|
||||
func (s internalSelector) DeepCopy() internalSelector {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
result := make([]Requirement, len(s))
|
||||
for i := range s {
|
||||
s[i].DeepCopyInto(&result[i])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (s internalSelector) DeepCopySelector() Selector {
|
||||
return s.DeepCopy()
|
||||
}
|
||||
|
||||
// ByKey sorts requirements by key to obtain deterministic parser
|
||||
type ByKey []Requirement
|
||||
|
||||
func (a ByKey) Len() int { return len(a) }
|
||||
|
||||
func (a ByKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
|
||||
func (a ByKey) Less(i, j int) bool { return a[i].key < a[j].key }
|
||||
|
||||
// Requirement contains values, a key, and an operator that relates the key and values.
|
||||
// The zero value of Requirement is invalid.
|
||||
// Requirement implements both set based match and exact match
|
||||
// Requirement should be initialized via NewRequirement constructor for creating a valid Requirement.
|
||||
type Requirement struct {
|
||||
key string
|
||||
operator selection.Operator
|
||||
// In huge majority of cases we have at most one value here.
|
||||
// It is generally faster to operate on a single-element slice
|
||||
// than on a single-element map, so we have a slice here.
|
||||
strValues []string
|
||||
}
|
||||
|
||||
// NewRequirement is the constructor for a Requirement.
|
||||
// If any of these rules is violated, an error is returned:
|
||||
// (1) The operator can only be In, NotIn, Equals, DoubleEquals, NotEquals, Exists, or DoesNotExist.
|
||||
// (2) If the operator is In or NotIn, the values set must be non-empty.
|
||||
// (3) If the operator is Equals, DoubleEquals, or NotEquals, the values set must contain one value.
|
||||
// (4) If the operator is Exists or DoesNotExist, the value set must be empty.
|
||||
// (5) If the operator is Gt or Lt, the values set must contain only one value, which will be interpreted as an integer.
|
||||
// (6) The key is invalid due to its length, or sequence
|
||||
// of characters. See validateLabelKey for more details.
|
||||
//
|
||||
// The empty string is a valid value in the input values set.
|
||||
func NewRequirement(key string, op selection.Operator, vals []string) (*Requirement, error) {
|
||||
if err := validateLabelKey(key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch op {
|
||||
case selection.In, selection.NotIn:
|
||||
if len(vals) == 0 {
|
||||
return nil, fmt.Errorf("for 'in', 'notin' operators, values set can't be empty")
|
||||
}
|
||||
case selection.Equals, selection.DoubleEquals, selection.NotEquals:
|
||||
if len(vals) != 1 {
|
||||
return nil, fmt.Errorf("exact-match compatibility requires one single value")
|
||||
}
|
||||
case selection.Exists, selection.DoesNotExist:
|
||||
if len(vals) != 0 {
|
||||
return nil, fmt.Errorf("values set must be empty for exists and does not exist")
|
||||
}
|
||||
case selection.GreaterThan, selection.LessThan:
|
||||
if len(vals) != 1 {
|
||||
return nil, fmt.Errorf("for 'Gt', 'Lt' operators, exactly one value is required")
|
||||
}
|
||||
for i := range vals {
|
||||
if _, err := strconv.ParseInt(vals[i], 10, 64); err != nil {
|
||||
return nil, fmt.Errorf("for 'Gt', 'Lt' operators, the value must be an integer")
|
||||
}
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("operator '%v' is not recognized", op)
|
||||
}
|
||||
|
||||
for i := range vals {
|
||||
if err := validateLabelValue(key, vals[i]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &Requirement{key: key, operator: op, strValues: vals}, nil
|
||||
}
|
||||
|
||||
func (r *Requirement) hasValue(value string) bool {
|
||||
for i := range r.strValues {
|
||||
if r.strValues[i] == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Matches returns true if the Requirement matches the input Labels.
|
||||
// There is a match in the following cases:
|
||||
// (1) The operator is Exists and Labels has the Requirement's key.
|
||||
// (2) The operator is In, Labels has the Requirement's key and Labels'
|
||||
// value for that key is in Requirement's value set.
|
||||
// (3) The operator is NotIn, Labels has the Requirement's key and
|
||||
// Labels' value for that key is not in Requirement's value set.
|
||||
// (4) The operator is DoesNotExist or NotIn and Labels does not have the
|
||||
// Requirement's key.
|
||||
// (5) The operator is GreaterThanOperator or LessThanOperator, and Labels has
|
||||
// the Requirement's key and the corresponding value satisfies mathematical inequality.
|
||||
func (r *Requirement) Matches(ls Labels) bool {
|
||||
switch r.operator {
|
||||
case selection.In, selection.Equals, selection.DoubleEquals:
|
||||
if !ls.Has(r.key) {
|
||||
return false
|
||||
}
|
||||
return r.hasValue(ls.Get(r.key))
|
||||
case selection.NotIn, selection.NotEquals:
|
||||
if !ls.Has(r.key) {
|
||||
return true
|
||||
}
|
||||
return !r.hasValue(ls.Get(r.key))
|
||||
case selection.Exists:
|
||||
return ls.Has(r.key)
|
||||
case selection.DoesNotExist:
|
||||
return !ls.Has(r.key)
|
||||
case selection.GreaterThan, selection.LessThan:
|
||||
if !ls.Has(r.key) {
|
||||
return false
|
||||
}
|
||||
lsValue, err := strconv.ParseInt(ls.Get(r.key), 10, 64)
|
||||
if err != nil {
|
||||
log.Printf("ParseInt failed for value %+v in label %+v, %+v", ls.Get(r.key), ls, err)
|
||||
return false
|
||||
}
|
||||
|
||||
// There should be only one strValue in r.strValues, and can be converted to an integer.
|
||||
if len(r.strValues) != 1 {
|
||||
log.Printf("Invalid values count %+v of requirement %#v, for 'Gt', 'Lt' operators, exactly one value is required", len(r.strValues), r)
|
||||
return false
|
||||
}
|
||||
|
||||
var rValue int64
|
||||
for i := range r.strValues {
|
||||
rValue, err = strconv.ParseInt(r.strValues[i], 10, 64)
|
||||
if err != nil {
|
||||
log.Printf("ParseInt failed for value %+v in requirement %#v, for 'Gt', 'Lt' operators, the value must be an integer", r.strValues[i], r)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return (r.operator == selection.GreaterThan && lsValue > rValue) || (r.operator == selection.LessThan && lsValue < rValue)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Key returns requirement key
|
||||
func (r *Requirement) Key() string {
|
||||
return r.key
|
||||
}
|
||||
|
||||
// Operator returns requirement operator
|
||||
func (r *Requirement) Operator() selection.Operator {
|
||||
return r.operator
|
||||
}
|
||||
|
||||
// Values returns requirement values
|
||||
func (r *Requirement) Values() sets.String {
|
||||
ret := sets.String{}
|
||||
for i := range r.strValues {
|
||||
ret.Insert(r.strValues[i])
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Empty returns true if the internalSelector doesn't restrict selection space
|
||||
func (lsel internalSelector) Empty() bool {
|
||||
if lsel == nil {
|
||||
return true
|
||||
}
|
||||
return len(lsel) == 0
|
||||
}
|
||||
|
||||
// String returns a human-readable string that represents this
|
||||
// Requirement. If called on an invalid Requirement, an error is
|
||||
// returned. See NewRequirement for creating a valid Requirement.
|
||||
func (r *Requirement) String() string {
|
||||
var buffer bytes.Buffer
|
||||
if r.operator == selection.DoesNotExist {
|
||||
buffer.WriteString("!")
|
||||
}
|
||||
buffer.WriteString(r.key)
|
||||
|
||||
switch r.operator {
|
||||
case selection.Equals:
|
||||
buffer.WriteString("=")
|
||||
case selection.DoubleEquals:
|
||||
buffer.WriteString("==")
|
||||
case selection.NotEquals:
|
||||
buffer.WriteString("!=")
|
||||
case selection.In:
|
||||
buffer.WriteString(" in ")
|
||||
case selection.NotIn:
|
||||
buffer.WriteString(" notin ")
|
||||
case selection.GreaterThan:
|
||||
buffer.WriteString(">")
|
||||
case selection.LessThan:
|
||||
buffer.WriteString("<")
|
||||
case selection.Exists, selection.DoesNotExist:
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
switch r.operator {
|
||||
case selection.In, selection.NotIn:
|
||||
buffer.WriteString("(")
|
||||
}
|
||||
if len(r.strValues) == 1 {
|
||||
buffer.WriteString(r.strValues[0])
|
||||
} else { // only > 1 since == 0 prohibited by NewRequirement
|
||||
// normalizes value order on output, without mutating the in-memory selector representation
|
||||
// also avoids normalization when it is not required, and ensures we do not mutate shared data
|
||||
buffer.WriteString(strings.Join(safeSort(r.strValues), ","))
|
||||
}
|
||||
|
||||
switch r.operator {
|
||||
case selection.In, selection.NotIn:
|
||||
buffer.WriteString(")")
|
||||
}
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// safeSort sort input strings without modification
|
||||
func safeSort(in []string) []string {
|
||||
if sort.StringsAreSorted(in) {
|
||||
return in
|
||||
}
|
||||
out := make([]string, len(in))
|
||||
copy(out, in)
|
||||
sort.Strings(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// Add adds requirements to the selector. It copies the current selector returning a new one
|
||||
func (lsel internalSelector) Add(reqs ...Requirement) Selector {
|
||||
var sel internalSelector
|
||||
for ix := range lsel {
|
||||
sel = append(sel, lsel[ix])
|
||||
}
|
||||
for _, r := range reqs {
|
||||
sel = append(sel, r)
|
||||
}
|
||||
sort.Sort(ByKey(sel))
|
||||
return sel
|
||||
}
|
||||
|
||||
// Matches for a internalSelector returns true if all
|
||||
// its Requirements match the input Labels. If any
|
||||
// Requirement does not match, false is returned.
|
||||
func (lsel internalSelector) Matches(l Labels) bool {
|
||||
for ix := range lsel {
|
||||
if matches := lsel[ix].Matches(l); !matches {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (lsel internalSelector) Requirements() (Requirements, bool) { return Requirements(lsel), true }
|
||||
|
||||
// String returns a comma-separated string of all
|
||||
// the internalSelector Requirements' human-readable strings.
|
||||
func (lsel internalSelector) String() string {
|
||||
var reqs []string
|
||||
for ix := range lsel {
|
||||
reqs = append(reqs, lsel[ix].String())
|
||||
}
|
||||
return strings.Join(reqs, ",")
|
||||
}
|
||||
|
||||
// RequiresExactMatch introspect whether a given selector requires a single specific field
|
||||
// to be set, and if so returns the value it requires.
|
||||
func (lsel internalSelector) RequiresExactMatch(label string) (value string, found bool) {
|
||||
for ix := range lsel {
|
||||
if lsel[ix].key == label {
|
||||
switch lsel[ix].operator {
|
||||
case selection.Equals, selection.DoubleEquals, selection.In:
|
||||
if len(lsel[ix].strValues) == 1 {
|
||||
return lsel[ix].strValues[0], true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Token represents constant definition for lexer token
|
||||
type Token int
|
||||
|
||||
const (
|
||||
// ErrorToken represents scan error
|
||||
ErrorToken Token = iota
|
||||
// EndOfStringToken represents end of string
|
||||
EndOfStringToken
|
||||
// ClosedParToken represents close parenthesis
|
||||
ClosedParToken
|
||||
// CommaToken represents the comma
|
||||
CommaToken
|
||||
// DoesNotExistToken represents logic not
|
||||
DoesNotExistToken
|
||||
// DoubleEqualsToken represents double equals
|
||||
DoubleEqualsToken
|
||||
// EqualsToken represents equal
|
||||
EqualsToken
|
||||
// GreaterThanToken represents greater than
|
||||
GreaterThanToken
|
||||
// IdentifierToken represents identifier, e.g. keys and values
|
||||
IdentifierToken
|
||||
// InToken represents in
|
||||
InToken
|
||||
// LessThanToken represents less than
|
||||
LessThanToken
|
||||
// NotEqualsToken represents not equal
|
||||
NotEqualsToken
|
||||
// NotInToken represents not in
|
||||
NotInToken
|
||||
// OpenParToken represents open parenthesis
|
||||
OpenParToken
|
||||
)
|
||||
|
||||
// string2token contains the mapping between lexer Token and token literal
|
||||
// (except IdentifierToken, EndOfStringToken and ErrorToken since it makes no sense)
|
||||
var string2token = map[string]Token{
|
||||
")": ClosedParToken,
|
||||
",": CommaToken,
|
||||
"!": DoesNotExistToken,
|
||||
"==": DoubleEqualsToken,
|
||||
"=": EqualsToken,
|
||||
">": GreaterThanToken,
|
||||
"in": InToken,
|
||||
"<": LessThanToken,
|
||||
"!=": NotEqualsToken,
|
||||
"notin": NotInToken,
|
||||
"(": OpenParToken,
|
||||
}
|
||||
|
||||
// ScannedItem contains the Token and the literal produced by the lexer.
|
||||
type ScannedItem struct {
|
||||
tok Token
|
||||
literal string
|
||||
}
|
||||
|
||||
// isWhitespace returns true if the rune is a space, tab, or newline.
|
||||
func isWhitespace(ch byte) bool {
|
||||
return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'
|
||||
}
|
||||
|
||||
// isSpecialSymbol detect if the character ch can be an operator
|
||||
func isSpecialSymbol(ch byte) bool {
|
||||
switch ch {
|
||||
case '=', '!', '(', ')', ',', '>', '<':
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Lexer represents the Lexer struct for label selector.
|
||||
// It contains necessary informationt to tokenize the input string
|
||||
type Lexer struct {
|
||||
// s stores the string to be tokenized
|
||||
s string
|
||||
// pos is the position currently tokenized
|
||||
pos int
|
||||
}
|
||||
|
||||
// read return the character currently lexed
|
||||
// increment the position and check the buffer overflow
|
||||
func (l *Lexer) read() (b byte) {
|
||||
b = 0
|
||||
if l.pos < len(l.s) {
|
||||
b = l.s[l.pos]
|
||||
l.pos++
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// unread 'undoes' the last read character
|
||||
func (l *Lexer) unread() {
|
||||
l.pos--
|
||||
}
|
||||
|
||||
// scanIDOrKeyword scans string to recognize literal token (for example 'in') or an identifier.
|
||||
func (l *Lexer) scanIDOrKeyword() (tok Token, lit string) {
|
||||
var buffer []byte
|
||||
IdentifierLoop:
|
||||
for {
|
||||
switch ch := l.read(); {
|
||||
case ch == 0:
|
||||
break IdentifierLoop
|
||||
case isSpecialSymbol(ch) || isWhitespace(ch):
|
||||
l.unread()
|
||||
break IdentifierLoop
|
||||
default:
|
||||
buffer = append(buffer, ch)
|
||||
}
|
||||
}
|
||||
s := string(buffer)
|
||||
if val, ok := string2token[s]; ok { // is a literal token?
|
||||
return val, s
|
||||
}
|
||||
return IdentifierToken, s // otherwise is an identifier
|
||||
}
|
||||
|
||||
// scanSpecialSymbol scans string starting with special symbol.
|
||||
// special symbol identify non literal operators. "!=", "==", "="
|
||||
func (l *Lexer) scanSpecialSymbol() (Token, string) {
|
||||
lastScannedItem := ScannedItem{}
|
||||
var buffer []byte
|
||||
SpecialSymbolLoop:
|
||||
for {
|
||||
switch ch := l.read(); {
|
||||
case ch == 0:
|
||||
break SpecialSymbolLoop
|
||||
case isSpecialSymbol(ch):
|
||||
buffer = append(buffer, ch)
|
||||
if token, ok := string2token[string(buffer)]; ok {
|
||||
lastScannedItem = ScannedItem{tok: token, literal: string(buffer)}
|
||||
} else if lastScannedItem.tok != 0 {
|
||||
l.unread()
|
||||
break SpecialSymbolLoop
|
||||
}
|
||||
default:
|
||||
l.unread()
|
||||
break SpecialSymbolLoop
|
||||
}
|
||||
}
|
||||
if lastScannedItem.tok == 0 {
|
||||
return ErrorToken, fmt.Sprintf("error expected: keyword found '%s'", buffer)
|
||||
}
|
||||
return lastScannedItem.tok, lastScannedItem.literal
|
||||
}
|
||||
|
||||
// skipWhiteSpaces consumes all blank characters
|
||||
// returning the first non blank character
|
||||
func (l *Lexer) skipWhiteSpaces(ch byte) byte {
|
||||
for {
|
||||
if !isWhitespace(ch) {
|
||||
return ch
|
||||
}
|
||||
ch = l.read()
|
||||
}
|
||||
}
|
||||
|
||||
// Lex returns a pair of Token and the literal
|
||||
// literal is meaningfull only for IdentifierToken token
|
||||
func (l *Lexer) Lex() (tok Token, lit string) {
|
||||
switch ch := l.skipWhiteSpaces(l.read()); {
|
||||
case ch == 0:
|
||||
return EndOfStringToken, ""
|
||||
case isSpecialSymbol(ch):
|
||||
l.unread()
|
||||
return l.scanSpecialSymbol()
|
||||
default:
|
||||
l.unread()
|
||||
return l.scanIDOrKeyword()
|
||||
}
|
||||
}
|
||||
|
||||
// Parser data structure contains the label selector parser data structure
|
||||
type Parser struct {
|
||||
l *Lexer
|
||||
scannedItems []ScannedItem
|
||||
position int
|
||||
}
|
||||
|
||||
// ParserContext represents context during parsing:
|
||||
// some literal for example 'in' and 'notin' can be
|
||||
// recognized as operator for example 'x in (a)' but
|
||||
// it can be recognized as value for example 'value in (in)'
|
||||
type ParserContext int
|
||||
|
||||
const (
|
||||
// KeyAndOperator represents key and operator
|
||||
KeyAndOperator ParserContext = iota
|
||||
// Values represents values
|
||||
Values
|
||||
)
|
||||
|
||||
// lookahead func returns the current token and string. No increment of current position
|
||||
func (p *Parser) lookahead(context ParserContext) (Token, string) {
|
||||
tok, lit := p.scannedItems[p.position].tok, p.scannedItems[p.position].literal
|
||||
if context == Values {
|
||||
switch tok {
|
||||
case InToken, NotInToken:
|
||||
tok = IdentifierToken
|
||||
}
|
||||
}
|
||||
return tok, lit
|
||||
}
|
||||
|
||||
// consume returns current token and string. Increments the position
|
||||
func (p *Parser) consume(context ParserContext) (Token, string) {
|
||||
p.position++
|
||||
tok, lit := p.scannedItems[p.position-1].tok, p.scannedItems[p.position-1].literal
|
||||
if context == Values {
|
||||
switch tok {
|
||||
case InToken, NotInToken:
|
||||
tok = IdentifierToken
|
||||
}
|
||||
}
|
||||
return tok, lit
|
||||
}
|
||||
|
||||
// scan runs through the input string and stores the ScannedItem in an array
|
||||
// Parser can now lookahead and consume the tokens
|
||||
func (p *Parser) scan() {
|
||||
for {
|
||||
token, literal := p.l.Lex()
|
||||
p.scannedItems = append(p.scannedItems, ScannedItem{token, literal})
|
||||
if token == EndOfStringToken {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parse runs the left recursive descending algorithm
|
||||
// on input string. It returns a list of Requirement objects.
|
||||
func (p *Parser) parse() (internalSelector, error) {
|
||||
p.scan() // init scannedItems
|
||||
|
||||
var requirements internalSelector
|
||||
for {
|
||||
tok, lit := p.lookahead(Values)
|
||||
switch tok {
|
||||
case IdentifierToken, DoesNotExistToken:
|
||||
r, err := p.parseRequirement()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse requirement: %v", err)
|
||||
}
|
||||
requirements = append(requirements, *r)
|
||||
t, l := p.consume(Values)
|
||||
switch t {
|
||||
case EndOfStringToken:
|
||||
return requirements, nil
|
||||
case CommaToken:
|
||||
t2, l2 := p.lookahead(Values)
|
||||
if t2 != IdentifierToken && t2 != DoesNotExistToken {
|
||||
return nil, fmt.Errorf("found '%s', expected: identifier after ','", l2)
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("found '%s', expected: ',' or 'end of string'", l)
|
||||
}
|
||||
case EndOfStringToken:
|
||||
return requirements, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("found '%s', expected: !, identifier, or 'end of string'", lit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parser) parseRequirement() (*Requirement, error) {
|
||||
key, operator, err := p.parseKeyAndInferOperator()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if operator == selection.Exists || operator == selection.DoesNotExist { // operator found lookahead set checked
|
||||
return NewRequirement(key, operator, []string{})
|
||||
}
|
||||
operator, err = p.parseOperator()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var values sets.String
|
||||
switch operator {
|
||||
case selection.In, selection.NotIn:
|
||||
values, err = p.parseValues()
|
||||
case selection.Equals, selection.DoubleEquals, selection.NotEquals, selection.GreaterThan, selection.LessThan:
|
||||
values, err = p.parseExactValue()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewRequirement(key, operator, values.List())
|
||||
|
||||
}
|
||||
|
||||
// parseKeyAndInferOperator parse literals.
|
||||
// in case of no operator '!, in, notin, ==, =, !=' are found
|
||||
// the 'exists' operator is inferred
|
||||
func (p *Parser) parseKeyAndInferOperator() (string, selection.Operator, error) {
|
||||
var operator selection.Operator
|
||||
tok, literal := p.consume(Values)
|
||||
if tok == DoesNotExistToken {
|
||||
operator = selection.DoesNotExist
|
||||
tok, literal = p.consume(Values)
|
||||
}
|
||||
if tok != IdentifierToken {
|
||||
err := fmt.Errorf("found '%s', expected: identifier", literal)
|
||||
return "", "", err
|
||||
}
|
||||
if err := validateLabelKey(literal); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
if t, _ := p.lookahead(Values); t == EndOfStringToken || t == CommaToken {
|
||||
if operator != selection.DoesNotExist {
|
||||
operator = selection.Exists
|
||||
}
|
||||
}
|
||||
return literal, operator, nil
|
||||
}
|
||||
|
||||
// parseOperator return operator and eventually matchType
|
||||
// matchType can be exact
|
||||
func (p *Parser) parseOperator() (op selection.Operator, err error) {
|
||||
tok, lit := p.consume(KeyAndOperator)
|
||||
switch tok {
|
||||
// DoesNotExistToken shouldn't be here because it's a unary operator, not a binary operator
|
||||
case InToken:
|
||||
op = selection.In
|
||||
case EqualsToken:
|
||||
op = selection.Equals
|
||||
case DoubleEqualsToken:
|
||||
op = selection.DoubleEquals
|
||||
case GreaterThanToken:
|
||||
op = selection.GreaterThan
|
||||
case LessThanToken:
|
||||
op = selection.LessThan
|
||||
case NotInToken:
|
||||
op = selection.NotIn
|
||||
case NotEqualsToken:
|
||||
op = selection.NotEquals
|
||||
default:
|
||||
return "", fmt.Errorf("found '%s', expected: '=', '!=', '==', 'in', notin'", lit)
|
||||
}
|
||||
return op, nil
|
||||
}
|
||||
|
||||
// parseValues parses the values for set based matching (x,y,z)
|
||||
func (p *Parser) parseValues() (sets.String, error) {
|
||||
tok, lit := p.consume(Values)
|
||||
if tok != OpenParToken {
|
||||
return nil, fmt.Errorf("found '%s' expected: '('", lit)
|
||||
}
|
||||
tok, lit = p.lookahead(Values)
|
||||
switch tok {
|
||||
case IdentifierToken, CommaToken:
|
||||
s, err := p.parseIdentifiersList() // handles general cases
|
||||
if err != nil {
|
||||
return s, err
|
||||
}
|
||||
if tok, _ = p.consume(Values); tok != ClosedParToken {
|
||||
return nil, fmt.Errorf("found '%s', expected: ')'", lit)
|
||||
}
|
||||
return s, nil
|
||||
case ClosedParToken: // handles "()"
|
||||
p.consume(Values)
|
||||
return sets.NewString(""), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("found '%s', expected: ',', ')' or identifier", lit)
|
||||
}
|
||||
}
|
||||
|
||||
// parseIdentifiersList parses a (possibly empty) list of
|
||||
// of comma separated (possibly empty) identifiers
|
||||
func (p *Parser) parseIdentifiersList() (sets.String, error) {
|
||||
s := sets.NewString()
|
||||
for {
|
||||
tok, lit := p.consume(Values)
|
||||
switch tok {
|
||||
case IdentifierToken:
|
||||
s.Insert(lit)
|
||||
tok2, lit2 := p.lookahead(Values)
|
||||
switch tok2 {
|
||||
case CommaToken:
|
||||
continue
|
||||
case ClosedParToken:
|
||||
return s, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("found '%s', expected: ',' or ')'", lit2)
|
||||
}
|
||||
case CommaToken: // handled here since we can have "(,"
|
||||
if s.Len() == 0 {
|
||||
s.Insert("") // to handle (,
|
||||
}
|
||||
tok2, _ := p.lookahead(Values)
|
||||
if tok2 == ClosedParToken {
|
||||
s.Insert("") // to handle ,) Double "" removed by StringSet
|
||||
return s, nil
|
||||
}
|
||||
if tok2 == CommaToken {
|
||||
p.consume(Values)
|
||||
s.Insert("") // to handle ,, Double "" removed by StringSet
|
||||
}
|
||||
default: // it can be operator
|
||||
return s, fmt.Errorf("found '%s', expected: ',', or identifier", lit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parseExactValue parses the only value for exact match style
|
||||
func (p *Parser) parseExactValue() (sets.String, error) {
|
||||
s := sets.NewString()
|
||||
tok, lit := p.lookahead(Values)
|
||||
if tok == EndOfStringToken || tok == CommaToken {
|
||||
s.Insert("")
|
||||
return s, nil
|
||||
}
|
||||
tok, lit = p.consume(Values)
|
||||
if tok == IdentifierToken {
|
||||
s.Insert(lit)
|
||||
return s, nil
|
||||
}
|
||||
return nil, fmt.Errorf("found '%s', expected: identifier", lit)
|
||||
}
|
||||
|
||||
// Parse takes a string representing a selector and returns a selector
|
||||
// object, or an error. This parsing function differs from ParseSelector
|
||||
// as they parse different selectors with different syntaxes.
|
||||
// The input will cause an error if it does not follow this form:
|
||||
//
|
||||
// <selector-syntax> ::= <requirement> | <requirement> "," <selector-syntax>
|
||||
// <requirement> ::= [!] KEY [ <set-based-restriction> | <exact-match-restriction> ]
|
||||
// <set-based-restriction> ::= "" | <inclusion-exclusion> <value-set>
|
||||
// <inclusion-exclusion> ::= <inclusion> | <exclusion>
|
||||
// <exclusion> ::= "notin"
|
||||
// <inclusion> ::= "in"
|
||||
// <value-set> ::= "(" <values> ")"
|
||||
// <values> ::= VALUE | VALUE "," <values>
|
||||
// <exact-match-restriction> ::= ["="|"=="|"!="] VALUE
|
||||
//
|
||||
// KEY is a sequence of one or more characters following [ DNS_SUBDOMAIN "/" ] DNS_LABEL. Max length is 63 characters.
|
||||
// VALUE is a sequence of zero or more characters "([A-Za-z0-9_-\.])". Max length is 63 characters.
|
||||
// Delimiter is white space: (' ', '\t')
|
||||
// Example of valid syntax:
|
||||
// "x in (foo,,baz),y,z notin ()"
|
||||
//
|
||||
// Note:
|
||||
// (1) Inclusion - " in " - denotes that the KEY exists and is equal to any of the
|
||||
// VALUEs in its requirement
|
||||
// (2) Exclusion - " notin " - denotes that the KEY is not equal to any
|
||||
// of the VALUEs in its requirement or does not exist
|
||||
// (3) The empty string is a valid VALUE
|
||||
// (4) A requirement with just a KEY - as in "y" above - denotes that
|
||||
// the KEY exists and can be any VALUE.
|
||||
// (5) A requirement with just !KEY requires that the KEY not exist.
|
||||
//
|
||||
func Parse(selector string) (Selector, error) {
|
||||
parsedSelector, err := parse(selector)
|
||||
if err == nil {
|
||||
return parsedSelector, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// parse parses the string representation of the selector and returns the internalSelector struct.
|
||||
// The callers of this method can then decide how to return the internalSelector struct to their
|
||||
// callers. This function has two callers now, one returns a Selector interface and the other
|
||||
// returns a list of requirements.
|
||||
func parse(selector string) (internalSelector, error) {
|
||||
p := &Parser{l: &Lexer{s: selector, pos: 0}}
|
||||
items, err := p.parse()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sort.Sort(ByKey(items)) // sort to grant determistic parsing
|
||||
return internalSelector(items), err
|
||||
}
|
||||
|
||||
func validateLabelKey(k string) error {
|
||||
if errs := validation.IsQualifiedName(k); len(errs) != 0 {
|
||||
return fmt.Errorf("invalid label key %q: %s", k, strings.Join(errs, "; "))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateLabelValue(k, v string) error {
|
||||
if errs := validation.IsValidLabelValue(v); len(errs) != 0 {
|
||||
return fmt.Errorf("invalid label value: %q: at key: %q: %s", v, k, strings.Join(errs, "; "))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SelectorFromSet returns a Selector which will match exactly the given Set. A
|
||||
// nil and empty Sets are considered equivalent to Everything().
|
||||
// It does not perform any validation, which means the server will reject
|
||||
// the request if the Set contains invalid values.
|
||||
func SelectorFromSet(ls Set) Selector {
|
||||
return SelectorFromValidatedSet(ls)
|
||||
}
|
||||
|
||||
// ValidatedSelectorFromSet returns a Selector which will match exactly the given Set. A
|
||||
// nil and empty Sets are considered equivalent to Everything().
|
||||
// The Set is validated client-side, which allows to catch errors early.
|
||||
func ValidatedSelectorFromSet(ls Set) (Selector, error) {
|
||||
if ls == nil || len(ls) == 0 {
|
||||
return internalSelector{}, nil
|
||||
}
|
||||
requirements := make([]Requirement, 0, len(ls))
|
||||
for label, value := range ls {
|
||||
r, err := NewRequirement(label, selection.Equals, []string{value})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
requirements = append(requirements, *r)
|
||||
}
|
||||
// sort to have deterministic string representation
|
||||
sort.Sort(ByKey(requirements))
|
||||
return internalSelector(requirements), nil
|
||||
}
|
||||
|
||||
// SelectorFromValidatedSet returns a Selector which will match exactly the given Set.
|
||||
// A nil and empty Sets are considered equivalent to Everything().
|
||||
// It assumes that Set is already validated and doesn't do any validation.
|
||||
func SelectorFromValidatedSet(ls Set) Selector {
|
||||
if ls == nil || len(ls) == 0 {
|
||||
return internalSelector{}
|
||||
}
|
||||
requirements := make([]Requirement, 0, len(ls))
|
||||
for label, value := range ls {
|
||||
requirements = append(requirements, Requirement{key: label, operator: selection.Equals, strValues: []string{value}})
|
||||
}
|
||||
// sort to have deterministic string representation
|
||||
sort.Sort(ByKey(requirements))
|
||||
return internalSelector(requirements)
|
||||
}
|
||||
|
||||
// ParseToRequirements takes a string representing a selector and returns a list of
|
||||
// requirements. This function is suitable for those callers that perform additional
|
||||
// processing on selector requirements.
|
||||
// See the documentation for Parse() function for more details.
|
||||
// TODO: Consider exporting the internalSelector type instead.
|
||||
func ParseToRequirements(selector string) ([]Requirement, error) {
|
||||
return parse(selector)
|
||||
}
|
||||
36
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/selection/operator.go
generated
vendored
Normal file
36
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/selection/operator.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
// Code generated by k8scopy from k8s.io/apimachinery@v0.19.8; DO NOT EDIT.
|
||||
// File content copied from k8s.io/apimachinery@v0.19.8/pkg/selection/operator.go
|
||||
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package selection
|
||||
|
||||
// Operator represents a key/field's relationship to value(s).
|
||||
// See labels.Requirement and fields.Requirement for more details.
|
||||
type Operator string
|
||||
|
||||
const (
|
||||
DoesNotExist Operator = "!"
|
||||
Equals Operator = "="
|
||||
DoubleEquals Operator = "=="
|
||||
In Operator = "in"
|
||||
NotEquals Operator = "!="
|
||||
NotIn Operator = "notin"
|
||||
Exists Operator = "exists"
|
||||
GreaterThan Operator = "gt"
|
||||
LessThan Operator = "lt"
|
||||
)
|
||||
252
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/errors/errors.go
generated
vendored
Normal file
252
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/errors/errors.go
generated
vendored
Normal file
@@ -0,0 +1,252 @@
|
||||
// Code generated by k8scopy from k8s.io/apimachinery@v0.19.8; DO NOT EDIT.
|
||||
// File content copied from k8s.io/apimachinery@v0.19.8/pkg/util/errors/errors.go
|
||||
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package errors
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/sets"
|
||||
)
|
||||
|
||||
// MessageCountMap contains occurrence for each error message.
|
||||
type MessageCountMap map[string]int
|
||||
|
||||
// Aggregate represents an object that contains multiple errors, but does not
|
||||
// necessarily have singular semantic meaning.
|
||||
// The aggregate can be used with `errors.Is()` to check for the occurrence of
|
||||
// a specific error type.
|
||||
// Errors.As() is not supported, because the caller presumably cares about a
|
||||
// specific error of potentially multiple that match the given type.
|
||||
type Aggregate interface {
|
||||
error
|
||||
Errors() []error
|
||||
Is(error) bool
|
||||
}
|
||||
|
||||
// NewAggregate converts a slice of errors into an Aggregate interface, which
|
||||
// is itself an implementation of the error interface. If the slice is empty,
|
||||
// this returns nil.
|
||||
// It will check if any of the element of input error list is nil, to avoid
|
||||
// nil pointer panic when call Error().
|
||||
func NewAggregate(errlist []error) Aggregate {
|
||||
if len(errlist) == 0 {
|
||||
return nil
|
||||
}
|
||||
// In case of input error list contains nil
|
||||
var errs []error
|
||||
for _, e := range errlist {
|
||||
if e != nil {
|
||||
errs = append(errs, e)
|
||||
}
|
||||
}
|
||||
if len(errs) == 0 {
|
||||
return nil
|
||||
}
|
||||
return aggregate(errs)
|
||||
}
|
||||
|
||||
// This helper implements the error and Errors interfaces. Keeping it private
|
||||
// prevents people from making an aggregate of 0 errors, which is not
|
||||
// an error, but does satisfy the error interface.
|
||||
type aggregate []error
|
||||
|
||||
// Error is part of the error interface.
|
||||
func (agg aggregate) Error() string {
|
||||
if len(agg) == 0 {
|
||||
// This should never happen, really.
|
||||
return ""
|
||||
}
|
||||
if len(agg) == 1 {
|
||||
return agg[0].Error()
|
||||
}
|
||||
seenerrs := sets.NewString()
|
||||
result := ""
|
||||
agg.visit(func(err error) bool {
|
||||
msg := err.Error()
|
||||
if seenerrs.Has(msg) {
|
||||
return false
|
||||
}
|
||||
seenerrs.Insert(msg)
|
||||
if len(seenerrs) > 1 {
|
||||
result += ", "
|
||||
}
|
||||
result += msg
|
||||
return false
|
||||
})
|
||||
if len(seenerrs) == 1 {
|
||||
return result
|
||||
}
|
||||
return "[" + result + "]"
|
||||
}
|
||||
|
||||
func (agg aggregate) Is(target error) bool {
|
||||
return agg.visit(func(err error) bool {
|
||||
return errors.Is(err, target)
|
||||
})
|
||||
}
|
||||
|
||||
func (agg aggregate) visit(f func(err error) bool) bool {
|
||||
for _, err := range agg {
|
||||
switch err := err.(type) {
|
||||
case aggregate:
|
||||
if match := err.visit(f); match {
|
||||
return match
|
||||
}
|
||||
case Aggregate:
|
||||
for _, nestedErr := range err.Errors() {
|
||||
if match := f(nestedErr); match {
|
||||
return match
|
||||
}
|
||||
}
|
||||
default:
|
||||
if match := f(err); match {
|
||||
return match
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Errors is part of the Aggregate interface.
|
||||
func (agg aggregate) Errors() []error {
|
||||
return []error(agg)
|
||||
}
|
||||
|
||||
// Matcher is used to match errors. Returns true if the error matches.
|
||||
type Matcher func(error) bool
|
||||
|
||||
// FilterOut removes all errors that match any of the matchers from the input
|
||||
// error. If the input is a singular error, only that error is tested. If the
|
||||
// input implements the Aggregate interface, the list of errors will be
|
||||
// processed recursively.
|
||||
//
|
||||
// This can be used, for example, to remove known-OK errors (such as io.EOF or
|
||||
// os.PathNotFound) from a list of errors.
|
||||
func FilterOut(err error, fns ...Matcher) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if agg, ok := err.(Aggregate); ok {
|
||||
return NewAggregate(filterErrors(agg.Errors(), fns...))
|
||||
}
|
||||
if !matchesError(err, fns...) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// matchesError returns true if any Matcher returns true
|
||||
func matchesError(err error, fns ...Matcher) bool {
|
||||
for _, fn := range fns {
|
||||
if fn(err) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// filterErrors returns any errors (or nested errors, if the list contains
|
||||
// nested Errors) for which all fns return false. If no errors
|
||||
// remain a nil list is returned. The resulting silec will have all
|
||||
// nested slices flattened as a side effect.
|
||||
func filterErrors(list []error, fns ...Matcher) []error {
|
||||
result := []error{}
|
||||
for _, err := range list {
|
||||
r := FilterOut(err, fns...)
|
||||
if r != nil {
|
||||
result = append(result, r)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Flatten takes an Aggregate, which may hold other Aggregates in arbitrary
|
||||
// nesting, and flattens them all into a single Aggregate, recursively.
|
||||
func Flatten(agg Aggregate) Aggregate {
|
||||
result := []error{}
|
||||
if agg == nil {
|
||||
return nil
|
||||
}
|
||||
for _, err := range agg.Errors() {
|
||||
if a, ok := err.(Aggregate); ok {
|
||||
r := Flatten(a)
|
||||
if r != nil {
|
||||
result = append(result, r.Errors()...)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
result = append(result, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return NewAggregate(result)
|
||||
}
|
||||
|
||||
// CreateAggregateFromMessageCountMap converts MessageCountMap Aggregate
|
||||
func CreateAggregateFromMessageCountMap(m MessageCountMap) Aggregate {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
result := make([]error, 0, len(m))
|
||||
for errStr, count := range m {
|
||||
var countStr string
|
||||
if count > 1 {
|
||||
countStr = fmt.Sprintf(" (repeated %v times)", count)
|
||||
}
|
||||
result = append(result, fmt.Errorf("%v%v", errStr, countStr))
|
||||
}
|
||||
return NewAggregate(result)
|
||||
}
|
||||
|
||||
// Reduce will return err or, if err is an Aggregate and only has one item,
|
||||
// the first item in the aggregate.
|
||||
func Reduce(err error) error {
|
||||
if agg, ok := err.(Aggregate); ok && err != nil {
|
||||
switch len(agg.Errors()) {
|
||||
case 1:
|
||||
return agg.Errors()[0]
|
||||
case 0:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// AggregateGoroutines runs the provided functions in parallel, stuffing all
|
||||
// non-nil errors into the returned Aggregate.
|
||||
// Returns nil if all the functions complete successfully.
|
||||
func AggregateGoroutines(funcs ...func() error) Aggregate {
|
||||
errChan := make(chan error, len(funcs))
|
||||
for _, f := range funcs {
|
||||
go func(f func() error) { errChan <- f() }(f)
|
||||
}
|
||||
errs := make([]error, 0)
|
||||
for i := 0; i < cap(errChan); i++ {
|
||||
if err := <-errChan; err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
return NewAggregate(errs)
|
||||
}
|
||||
|
||||
// ErrPreconditionViolated is returned when the precondition is violated
|
||||
var ErrPreconditionViolated = errors.New("precondition is violated")
|
||||
24
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/sets/empty.go
generated
vendored
Normal file
24
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/sets/empty.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Code generated by k8scopy from k8s.io/apimachinery@v0.19.8; DO NOT EDIT.
|
||||
// File content copied from k8s.io/apimachinery@v0.19.8/pkg/util/sets/empty.go
|
||||
|
||||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package sets
|
||||
|
||||
// Empty is public since it is used by some internal API objects for conversions between external
|
||||
// string arrays and internal sets, and conversion logic requires public types today.
|
||||
type Empty struct{}
|
||||
206
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/sets/string.go
generated
vendored
Normal file
206
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/sets/string.go
generated
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
// Code generated by k8scopy from k8s.io/apimachinery@v0.19.8; DO NOT EDIT.
|
||||
// File content copied from k8s.io/apimachinery@v0.19.8/pkg/util/sets/string.go
|
||||
|
||||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package sets
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// sets.String is a set of strings, implemented via map[string]struct{} for minimal memory consumption.
|
||||
type String map[string]Empty
|
||||
|
||||
// NewString creates a String from a list of values.
|
||||
func NewString(items ...string) String {
|
||||
ss := String{}
|
||||
ss.Insert(items...)
|
||||
return ss
|
||||
}
|
||||
|
||||
// StringKeySet creates a String from a keys of a map[string](? extends interface{}).
|
||||
// If the value passed in is not actually a map, this will panic.
|
||||
func StringKeySet(theMap interface{}) String {
|
||||
v := reflect.ValueOf(theMap)
|
||||
ret := String{}
|
||||
|
||||
for _, keyValue := range v.MapKeys() {
|
||||
ret.Insert(keyValue.Interface().(string))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Insert adds items to the set.
|
||||
func (s String) Insert(items ...string) String {
|
||||
for _, item := range items {
|
||||
s[item] = Empty{}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Delete removes all items from the set.
|
||||
func (s String) Delete(items ...string) String {
|
||||
for _, item := range items {
|
||||
delete(s, item)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Has returns true if and only if item is contained in the set.
|
||||
func (s String) Has(item string) bool {
|
||||
_, contained := s[item]
|
||||
return contained
|
||||
}
|
||||
|
||||
// HasAll returns true if and only if all items are contained in the set.
|
||||
func (s String) HasAll(items ...string) bool {
|
||||
for _, item := range items {
|
||||
if !s.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// HasAny returns true if any items are contained in the set.
|
||||
func (s String) HasAny(items ...string) bool {
|
||||
for _, item := range items {
|
||||
if s.Has(item) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Difference returns a set of objects that are not in s2
|
||||
// For example:
|
||||
// s1 = {a1, a2, a3}
|
||||
// s2 = {a1, a2, a4, a5}
|
||||
// s1.Difference(s2) = {a3}
|
||||
// s2.Difference(s1) = {a4, a5}
|
||||
func (s String) Difference(s2 String) String {
|
||||
result := NewString()
|
||||
for key := range s {
|
||||
if !s2.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Union returns a new set which includes items in either s1 or s2.
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a3, a4}
|
||||
// s1.Union(s2) = {a1, a2, a3, a4}
|
||||
// s2.Union(s1) = {a1, a2, a3, a4}
|
||||
func (s1 String) Union(s2 String) String {
|
||||
result := NewString()
|
||||
for key := range s1 {
|
||||
result.Insert(key)
|
||||
}
|
||||
for key := range s2 {
|
||||
result.Insert(key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Intersection returns a new set which includes the item in BOTH s1 and s2
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a2, a3}
|
||||
// s1.Intersection(s2) = {a2}
|
||||
func (s1 String) Intersection(s2 String) String {
|
||||
var walk, other String
|
||||
result := NewString()
|
||||
if s1.Len() < s2.Len() {
|
||||
walk = s1
|
||||
other = s2
|
||||
} else {
|
||||
walk = s2
|
||||
other = s1
|
||||
}
|
||||
for key := range walk {
|
||||
if other.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// IsSuperset returns true if and only if s1 is a superset of s2.
|
||||
func (s1 String) IsSuperset(s2 String) bool {
|
||||
for item := range s2 {
|
||||
if !s1.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal returns true if and only if s1 is equal (as a set) to s2.
|
||||
// Two sets are equal if their membership is identical.
|
||||
// (In practice, this means same elements, order doesn't matter)
|
||||
func (s1 String) Equal(s2 String) bool {
|
||||
return len(s1) == len(s2) && s1.IsSuperset(s2)
|
||||
}
|
||||
|
||||
type sortableSliceOfString []string
|
||||
|
||||
func (s sortableSliceOfString) Len() int { return len(s) }
|
||||
func (s sortableSliceOfString) Less(i, j int) bool { return lessString(s[i], s[j]) }
|
||||
func (s sortableSliceOfString) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// List returns the contents as a sorted string slice.
|
||||
func (s String) List() []string {
|
||||
res := make(sortableSliceOfString, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
sort.Sort(res)
|
||||
return []string(res)
|
||||
}
|
||||
|
||||
// UnsortedList returns the slice with contents in random order.
|
||||
func (s String) UnsortedList() []string {
|
||||
res := make([]string, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Returns a single element from the set.
|
||||
func (s String) PopAny() (string, bool) {
|
||||
for key := range s {
|
||||
s.Delete(key)
|
||||
return key, true
|
||||
}
|
||||
var zeroValue string
|
||||
return zeroValue, false
|
||||
}
|
||||
|
||||
// Len returns the size of the set.
|
||||
func (s String) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func lessString(lhs, rhs string) bool {
|
||||
return lhs < rhs
|
||||
}
|
||||
275
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/validation/field/errors.go
generated
vendored
Normal file
275
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/validation/field/errors.go
generated
vendored
Normal file
@@ -0,0 +1,275 @@
|
||||
// Code generated by k8scopy from k8s.io/apimachinery@v0.19.8; DO NOT EDIT.
|
||||
// File content copied from k8s.io/apimachinery@v0.19.8/pkg/util/validation/field/errors.go
|
||||
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package field
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
utilerrors "sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/sets"
|
||||
)
|
||||
|
||||
// Error is an implementation of the 'error' interface, which represents a
|
||||
// field-level validation error.
|
||||
type Error struct {
|
||||
Type ErrorType
|
||||
Field string
|
||||
BadValue interface{}
|
||||
Detail string
|
||||
}
|
||||
|
||||
var _ error = &Error{}
|
||||
|
||||
// Error implements the error interface.
|
||||
func (v *Error) Error() string {
|
||||
return fmt.Sprintf("%s: %s", v.Field, v.ErrorBody())
|
||||
}
|
||||
|
||||
// ErrorBody returns the error message without the field name. This is useful
|
||||
// for building nice-looking higher-level error reporting.
|
||||
func (v *Error) ErrorBody() string {
|
||||
var s string
|
||||
switch v.Type {
|
||||
case ErrorTypeRequired, ErrorTypeForbidden, ErrorTypeTooLong, ErrorTypeInternal:
|
||||
s = v.Type.String()
|
||||
default:
|
||||
value := v.BadValue
|
||||
valueType := reflect.TypeOf(value)
|
||||
if value == nil || valueType == nil {
|
||||
value = "null"
|
||||
} else if valueType.Kind() == reflect.Ptr {
|
||||
if reflectValue := reflect.ValueOf(value); reflectValue.IsNil() {
|
||||
value = "null"
|
||||
} else {
|
||||
value = reflectValue.Elem().Interface()
|
||||
}
|
||||
}
|
||||
switch t := value.(type) {
|
||||
case int64, int32, float64, float32, bool:
|
||||
// use simple printer for simple types
|
||||
s = fmt.Sprintf("%s: %v", v.Type, value)
|
||||
case string:
|
||||
s = fmt.Sprintf("%s: %q", v.Type, t)
|
||||
case fmt.Stringer:
|
||||
// anything that defines String() is better than raw struct
|
||||
s = fmt.Sprintf("%s: %s", v.Type, t.String())
|
||||
default:
|
||||
// fallback to raw struct
|
||||
// TODO: internal types have panic guards against json.Marshalling to prevent
|
||||
// accidental use of internal types in external serialized form. For now, use
|
||||
// %#v, although it would be better to show a more expressive output in the future
|
||||
s = fmt.Sprintf("%s: %#v", v.Type, value)
|
||||
}
|
||||
}
|
||||
if len(v.Detail) != 0 {
|
||||
s += fmt.Sprintf(": %s", v.Detail)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// ErrorType is a machine readable value providing more detail about why
|
||||
// a field is invalid. These values are expected to match 1-1 with
|
||||
// CauseType in api/types.go.
|
||||
type ErrorType string
|
||||
|
||||
// TODO: These values are duplicated in api/types.go, but there's a circular dep. Fix it.
|
||||
const (
|
||||
// ErrorTypeNotFound is used to report failure to find a requested value
|
||||
// (e.g. looking up an ID). See NotFound().
|
||||
ErrorTypeNotFound ErrorType = "FieldValueNotFound"
|
||||
// ErrorTypeRequired is used to report required values that are not
|
||||
// provided (e.g. empty strings, null values, or empty arrays). See
|
||||
// Required().
|
||||
ErrorTypeRequired ErrorType = "FieldValueRequired"
|
||||
// ErrorTypeDuplicate is used to report collisions of values that must be
|
||||
// unique (e.g. unique IDs). See Duplicate().
|
||||
ErrorTypeDuplicate ErrorType = "FieldValueDuplicate"
|
||||
// ErrorTypeInvalid is used to report malformed values (e.g. failed regex
|
||||
// match, too long, out of bounds). See Invalid().
|
||||
ErrorTypeInvalid ErrorType = "FieldValueInvalid"
|
||||
// ErrorTypeNotSupported is used to report unknown values for enumerated
|
||||
// fields (e.g. a list of valid values). See NotSupported().
|
||||
ErrorTypeNotSupported ErrorType = "FieldValueNotSupported"
|
||||
// ErrorTypeForbidden is used to report valid (as per formatting rules)
|
||||
// values which would be accepted under some conditions, but which are not
|
||||
// permitted by the current conditions (such as security policy). See
|
||||
// Forbidden().
|
||||
ErrorTypeForbidden ErrorType = "FieldValueForbidden"
|
||||
// ErrorTypeTooLong is used to report that the given value is too long.
|
||||
// This is similar to ErrorTypeInvalid, but the error will not include the
|
||||
// too-long value. See TooLong().
|
||||
ErrorTypeTooLong ErrorType = "FieldValueTooLong"
|
||||
// ErrorTypeTooMany is used to report "too many". This is used to
|
||||
// report that a given list has too many items. This is similar to FieldValueTooLong,
|
||||
// but the error indicates quantity instead of length.
|
||||
ErrorTypeTooMany ErrorType = "FieldValueTooMany"
|
||||
// ErrorTypeInternal is used to report other errors that are not related
|
||||
// to user input. See InternalError().
|
||||
ErrorTypeInternal ErrorType = "InternalError"
|
||||
)
|
||||
|
||||
// String converts a ErrorType into its corresponding canonical error message.
|
||||
func (t ErrorType) String() string {
|
||||
switch t {
|
||||
case ErrorTypeNotFound:
|
||||
return "Not found"
|
||||
case ErrorTypeRequired:
|
||||
return "Required value"
|
||||
case ErrorTypeDuplicate:
|
||||
return "Duplicate value"
|
||||
case ErrorTypeInvalid:
|
||||
return "Invalid value"
|
||||
case ErrorTypeNotSupported:
|
||||
return "Unsupported value"
|
||||
case ErrorTypeForbidden:
|
||||
return "Forbidden"
|
||||
case ErrorTypeTooLong:
|
||||
return "Too long"
|
||||
case ErrorTypeTooMany:
|
||||
return "Too many"
|
||||
case ErrorTypeInternal:
|
||||
return "Internal error"
|
||||
default:
|
||||
panic(fmt.Sprintf("unrecognized validation error: %q", string(t)))
|
||||
}
|
||||
}
|
||||
|
||||
// NotFound returns a *Error indicating "value not found". This is
|
||||
// used to report failure to find a requested value (e.g. looking up an ID).
|
||||
func NotFound(field *Path, value interface{}) *Error {
|
||||
return &Error{ErrorTypeNotFound, field.String(), value, ""}
|
||||
}
|
||||
|
||||
// Required returns a *Error indicating "value required". This is used
|
||||
// to report required values that are not provided (e.g. empty strings, null
|
||||
// values, or empty arrays).
|
||||
func Required(field *Path, detail string) *Error {
|
||||
return &Error{ErrorTypeRequired, field.String(), "", detail}
|
||||
}
|
||||
|
||||
// Duplicate returns a *Error indicating "duplicate value". This is
|
||||
// used to report collisions of values that must be unique (e.g. names or IDs).
|
||||
func Duplicate(field *Path, value interface{}) *Error {
|
||||
return &Error{ErrorTypeDuplicate, field.String(), value, ""}
|
||||
}
|
||||
|
||||
// Invalid returns a *Error indicating "invalid value". This is used
|
||||
// to report malformed values (e.g. failed regex match, too long, out of bounds).
|
||||
func Invalid(field *Path, value interface{}, detail string) *Error {
|
||||
return &Error{ErrorTypeInvalid, field.String(), value, detail}
|
||||
}
|
||||
|
||||
// NotSupported returns a *Error indicating "unsupported value".
|
||||
// This is used to report unknown values for enumerated fields (e.g. a list of
|
||||
// valid values).
|
||||
func NotSupported(field *Path, value interface{}, validValues []string) *Error {
|
||||
detail := ""
|
||||
if validValues != nil && len(validValues) > 0 {
|
||||
quotedValues := make([]string, len(validValues))
|
||||
for i, v := range validValues {
|
||||
quotedValues[i] = strconv.Quote(v)
|
||||
}
|
||||
detail = "supported values: " + strings.Join(quotedValues, ", ")
|
||||
}
|
||||
return &Error{ErrorTypeNotSupported, field.String(), value, detail}
|
||||
}
|
||||
|
||||
// Forbidden returns a *Error indicating "forbidden". This is used to
|
||||
// report valid (as per formatting rules) values which would be accepted under
|
||||
// some conditions, but which are not permitted by current conditions (e.g.
|
||||
// security policy).
|
||||
func Forbidden(field *Path, detail string) *Error {
|
||||
return &Error{ErrorTypeForbidden, field.String(), "", detail}
|
||||
}
|
||||
|
||||
// TooLong returns a *Error indicating "too long". This is used to
|
||||
// report that the given value is too long. This is similar to
|
||||
// Invalid, but the returned error will not include the too-long
|
||||
// value.
|
||||
func TooLong(field *Path, value interface{}, maxLength int) *Error {
|
||||
return &Error{ErrorTypeTooLong, field.String(), value, fmt.Sprintf("must have at most %d bytes", maxLength)}
|
||||
}
|
||||
|
||||
// TooMany returns a *Error indicating "too many". This is used to
|
||||
// report that a given list has too many items. This is similar to TooLong,
|
||||
// but the returned error indicates quantity instead of length.
|
||||
func TooMany(field *Path, actualQuantity, maxQuantity int) *Error {
|
||||
return &Error{ErrorTypeTooMany, field.String(), actualQuantity, fmt.Sprintf("must have at most %d items", maxQuantity)}
|
||||
}
|
||||
|
||||
// InternalError returns a *Error indicating "internal error". This is used
|
||||
// to signal that an error was found that was not directly related to user
|
||||
// input. The err argument must be non-nil.
|
||||
func InternalError(field *Path, err error) *Error {
|
||||
return &Error{ErrorTypeInternal, field.String(), nil, err.Error()}
|
||||
}
|
||||
|
||||
// ErrorList holds a set of Errors. It is plausible that we might one day have
|
||||
// non-field errors in this same umbrella package, but for now we don't, so
|
||||
// we can keep it simple and leave ErrorList here.
|
||||
type ErrorList []*Error
|
||||
|
||||
// NewErrorTypeMatcher returns an errors.Matcher that returns true
|
||||
// if the provided error is a Error and has the provided ErrorType.
|
||||
func NewErrorTypeMatcher(t ErrorType) utilerrors.Matcher {
|
||||
return func(err error) bool {
|
||||
if e, ok := err.(*Error); ok {
|
||||
return e.Type == t
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// ToAggregate converts the ErrorList into an errors.Aggregate.
|
||||
func (list ErrorList) ToAggregate() utilerrors.Aggregate {
|
||||
errs := make([]error, 0, len(list))
|
||||
errorMsgs := sets.NewString()
|
||||
for _, err := range list {
|
||||
msg := fmt.Sprintf("%v", err)
|
||||
if errorMsgs.Has(msg) {
|
||||
continue
|
||||
}
|
||||
errorMsgs.Insert(msg)
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return utilerrors.NewAggregate(errs)
|
||||
}
|
||||
|
||||
func fromAggregate(agg utilerrors.Aggregate) ErrorList {
|
||||
errs := agg.Errors()
|
||||
list := make(ErrorList, len(errs))
|
||||
for i := range errs {
|
||||
list[i] = errs[i].(*Error)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// Filter removes items from the ErrorList that match the provided fns.
|
||||
func (list ErrorList) Filter(fns ...utilerrors.Matcher) ErrorList {
|
||||
err := utilerrors.FilterOut(list.ToAggregate(), fns...)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
// FilterOut takes an Aggregate and returns an Aggregate
|
||||
return fromAggregate(err.(utilerrors.Aggregate))
|
||||
}
|
||||
94
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/validation/field/path.go
generated
vendored
Normal file
94
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/validation/field/path.go
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
// Code generated by k8scopy from k8s.io/apimachinery@v0.19.8; DO NOT EDIT.
|
||||
// File content copied from k8s.io/apimachinery@v0.19.8/pkg/util/validation/field/path.go
|
||||
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package field
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Path represents the path from some root to a particular field.
|
||||
type Path struct {
|
||||
name string // the name of this field or "" if this is an index
|
||||
index string // if name == "", this is a subscript (index or map key) of the previous element
|
||||
parent *Path // nil if this is the root element
|
||||
}
|
||||
|
||||
// NewPath creates a root Path object.
|
||||
func NewPath(name string, moreNames ...string) *Path {
|
||||
r := &Path{name: name, parent: nil}
|
||||
for _, anotherName := range moreNames {
|
||||
r = &Path{name: anotherName, parent: r}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// Root returns the root element of this Path.
|
||||
func (p *Path) Root() *Path {
|
||||
for ; p.parent != nil; p = p.parent {
|
||||
// Do nothing.
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Child creates a new Path that is a child of the method receiver.
|
||||
func (p *Path) Child(name string, moreNames ...string) *Path {
|
||||
r := NewPath(name, moreNames...)
|
||||
r.Root().parent = p
|
||||
return r
|
||||
}
|
||||
|
||||
// Index indicates that the previous Path is to be subscripted by an int.
|
||||
// This sets the same underlying value as Key.
|
||||
func (p *Path) Index(index int) *Path {
|
||||
return &Path{index: strconv.Itoa(index), parent: p}
|
||||
}
|
||||
|
||||
// Key indicates that the previous Path is to be subscripted by a string.
|
||||
// This sets the same underlying value as Index.
|
||||
func (p *Path) Key(key string) *Path {
|
||||
return &Path{index: key, parent: p}
|
||||
}
|
||||
|
||||
// String produces a string representation of the Path.
|
||||
func (p *Path) String() string {
|
||||
// make a slice to iterate
|
||||
elems := []*Path{}
|
||||
for ; p != nil; p = p.parent {
|
||||
elems = append(elems, p)
|
||||
}
|
||||
|
||||
// iterate, but it has to be backwards
|
||||
buf := bytes.NewBuffer(nil)
|
||||
for i := range elems {
|
||||
p := elems[len(elems)-1-i]
|
||||
if p.parent != nil && len(p.name) > 0 {
|
||||
// This is either the root or it is a subscript.
|
||||
buf.WriteString(".")
|
||||
}
|
||||
if len(p.name) > 0 {
|
||||
buf.WriteString(p.name)
|
||||
} else {
|
||||
fmt.Fprintf(buf, "[%s]", p.index)
|
||||
}
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
506
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/validation/validation.go
generated
vendored
Normal file
506
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/validation/validation.go
generated
vendored
Normal file
@@ -0,0 +1,506 @@
|
||||
// Code generated by k8scopy from k8s.io/apimachinery@v0.19.8; DO NOT EDIT.
|
||||
// File content copied from k8s.io/apimachinery@v0.19.8/pkg/util/validation/validation.go
|
||||
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package validation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"net"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/validation/field"
|
||||
)
|
||||
|
||||
const qnameCharFmt string = "[A-Za-z0-9]"
|
||||
const qnameExtCharFmt string = "[-A-Za-z0-9_.]"
|
||||
const qualifiedNameFmt string = "(" + qnameCharFmt + qnameExtCharFmt + "*)?" + qnameCharFmt
|
||||
const qualifiedNameErrMsg string = "must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character"
|
||||
const qualifiedNameMaxLength int = 63
|
||||
|
||||
var qualifiedNameRegexp = regexp.MustCompile("^" + qualifiedNameFmt + "$")
|
||||
|
||||
// IsQualifiedName tests whether the value passed is what Kubernetes calls a
|
||||
// "qualified name". This is a format used in various places throughout the
|
||||
// system. If the value is not valid, a list of error strings is returned.
|
||||
// Otherwise an empty list (or nil) is returned.
|
||||
func IsQualifiedName(value string) []string {
|
||||
var errs []string
|
||||
parts := strings.Split(value, "/")
|
||||
var name string
|
||||
switch len(parts) {
|
||||
case 1:
|
||||
name = parts[0]
|
||||
case 2:
|
||||
var prefix string
|
||||
prefix, name = parts[0], parts[1]
|
||||
if len(prefix) == 0 {
|
||||
errs = append(errs, "prefix part "+EmptyError())
|
||||
} else if msgs := IsDNS1123Subdomain(prefix); len(msgs) != 0 {
|
||||
errs = append(errs, prefixEach(msgs, "prefix part ")...)
|
||||
}
|
||||
default:
|
||||
return append(errs, "a qualified name "+RegexError(qualifiedNameErrMsg, qualifiedNameFmt, "MyName", "my.name", "123-abc")+
|
||||
" with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyName')")
|
||||
}
|
||||
|
||||
if len(name) == 0 {
|
||||
errs = append(errs, "name part "+EmptyError())
|
||||
} else if len(name) > qualifiedNameMaxLength {
|
||||
errs = append(errs, "name part "+MaxLenError(qualifiedNameMaxLength))
|
||||
}
|
||||
if !qualifiedNameRegexp.MatchString(name) {
|
||||
errs = append(errs, "name part "+RegexError(qualifiedNameErrMsg, qualifiedNameFmt, "MyName", "my.name", "123-abc"))
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
// IsFullyQualifiedName checks if the name is fully qualified. This is similar
|
||||
// to IsFullyQualifiedDomainName but requires a minimum of 3 segments instead of
|
||||
// 2 and does not accept a trailing . as valid.
|
||||
// TODO: This function is deprecated and preserved until all callers migrate to
|
||||
// IsFullyQualifiedDomainName; please don't add new callers.
|
||||
func IsFullyQualifiedName(fldPath *field.Path, name string) field.ErrorList {
|
||||
var allErrors field.ErrorList
|
||||
if len(name) == 0 {
|
||||
return append(allErrors, field.Required(fldPath, ""))
|
||||
}
|
||||
if errs := IsDNS1123Subdomain(name); len(errs) > 0 {
|
||||
return append(allErrors, field.Invalid(fldPath, name, strings.Join(errs, ",")))
|
||||
}
|
||||
if len(strings.Split(name, ".")) < 3 {
|
||||
return append(allErrors, field.Invalid(fldPath, name, "should be a domain with at least three segments separated by dots"))
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
// IsFullyQualifiedDomainName checks if the domain name is fully qualified. This
|
||||
// is similar to IsFullyQualifiedName but only requires a minimum of 2 segments
|
||||
// instead of 3 and accepts a trailing . as valid.
|
||||
func IsFullyQualifiedDomainName(fldPath *field.Path, name string) field.ErrorList {
|
||||
var allErrors field.ErrorList
|
||||
if len(name) == 0 {
|
||||
return append(allErrors, field.Required(fldPath, ""))
|
||||
}
|
||||
if strings.HasSuffix(name, ".") {
|
||||
name = name[:len(name)-1]
|
||||
}
|
||||
if errs := IsDNS1123Subdomain(name); len(errs) > 0 {
|
||||
return append(allErrors, field.Invalid(fldPath, name, strings.Join(errs, ",")))
|
||||
}
|
||||
if len(strings.Split(name, ".")) < 2 {
|
||||
return append(allErrors, field.Invalid(fldPath, name, "should be a domain with at least two segments separated by dots"))
|
||||
}
|
||||
for _, label := range strings.Split(name, ".") {
|
||||
if errs := IsDNS1123Label(label); len(errs) > 0 {
|
||||
return append(allErrors, field.Invalid(fldPath, label, strings.Join(errs, ",")))
|
||||
}
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
// Allowed characters in an HTTP Path as defined by RFC 3986. A HTTP path may
|
||||
// contain:
|
||||
// * unreserved characters (alphanumeric, '-', '.', '_', '~')
|
||||
// * percent-encoded octets
|
||||
// * sub-delims ("!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "=")
|
||||
// * a colon character (":")
|
||||
const httpPathFmt string = `[A-Za-z0-9/\-._~%!$&'()*+,;=:]+`
|
||||
|
||||
var httpPathRegexp = regexp.MustCompile("^" + httpPathFmt + "$")
|
||||
|
||||
// IsDomainPrefixedPath checks if the given string is a domain-prefixed path
|
||||
// (e.g. acme.io/foo). All characters before the first "/" must be a valid
|
||||
// subdomain as defined by RFC 1123. All characters trailing the first "/" must
|
||||
// be valid HTTP Path characters as defined by RFC 3986.
|
||||
func IsDomainPrefixedPath(fldPath *field.Path, dpPath string) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
if len(dpPath) == 0 {
|
||||
return append(allErrs, field.Required(fldPath, ""))
|
||||
}
|
||||
|
||||
segments := strings.SplitN(dpPath, "/", 2)
|
||||
if len(segments) != 2 || len(segments[0]) == 0 || len(segments[1]) == 0 {
|
||||
return append(allErrs, field.Invalid(fldPath, dpPath, "must be a domain-prefixed path (such as \"acme.io/foo\")"))
|
||||
}
|
||||
|
||||
host := segments[0]
|
||||
for _, err := range IsDNS1123Subdomain(host) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, host, err))
|
||||
}
|
||||
|
||||
path := segments[1]
|
||||
if !httpPathRegexp.MatchString(path) {
|
||||
return append(allErrs, field.Invalid(fldPath, path, RegexError("Invalid path", httpPathFmt)))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
const labelValueFmt string = "(" + qualifiedNameFmt + ")?"
|
||||
const labelValueErrMsg string = "a valid label must be an empty string or consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character"
|
||||
|
||||
// LabelValueMaxLength is a label's max length
|
||||
const LabelValueMaxLength int = 63
|
||||
|
||||
var labelValueRegexp = regexp.MustCompile("^" + labelValueFmt + "$")
|
||||
|
||||
// IsValidLabelValue tests whether the value passed is a valid label value. If
|
||||
// the value is not valid, a list of error strings is returned. Otherwise an
|
||||
// empty list (or nil) is returned.
|
||||
func IsValidLabelValue(value string) []string {
|
||||
var errs []string
|
||||
if len(value) > LabelValueMaxLength {
|
||||
errs = append(errs, MaxLenError(LabelValueMaxLength))
|
||||
}
|
||||
if !labelValueRegexp.MatchString(value) {
|
||||
errs = append(errs, RegexError(labelValueErrMsg, labelValueFmt, "MyValue", "my_value", "12345"))
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
const dns1123LabelFmt string = "[a-z0-9]([-a-z0-9]*[a-z0-9])?"
|
||||
const dns1123LabelErrMsg string = "a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character"
|
||||
|
||||
// DNS1123LabelMaxLength is a label's max length in DNS (RFC 1123)
|
||||
const DNS1123LabelMaxLength int = 63
|
||||
|
||||
var dns1123LabelRegexp = regexp.MustCompile("^" + dns1123LabelFmt + "$")
|
||||
|
||||
// IsDNS1123Label tests for a string that conforms to the definition of a label in
|
||||
// DNS (RFC 1123).
|
||||
func IsDNS1123Label(value string) []string {
|
||||
var errs []string
|
||||
if len(value) > DNS1123LabelMaxLength {
|
||||
errs = append(errs, MaxLenError(DNS1123LabelMaxLength))
|
||||
}
|
||||
if !dns1123LabelRegexp.MatchString(value) {
|
||||
errs = append(errs, RegexError(dns1123LabelErrMsg, dns1123LabelFmt, "my-name", "123-abc"))
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
const dns1123SubdomainFmt string = dns1123LabelFmt + "(\\." + dns1123LabelFmt + ")*"
|
||||
const dns1123SubdomainErrorMsg string = "a DNS-1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character"
|
||||
|
||||
// DNS1123SubdomainMaxLength is a subdomain's max length in DNS (RFC 1123)
|
||||
const DNS1123SubdomainMaxLength int = 253
|
||||
|
||||
var dns1123SubdomainRegexp = regexp.MustCompile("^" + dns1123SubdomainFmt + "$")
|
||||
|
||||
// IsDNS1123Subdomain tests for a string that conforms to the definition of a
|
||||
// subdomain in DNS (RFC 1123).
|
||||
func IsDNS1123Subdomain(value string) []string {
|
||||
var errs []string
|
||||
if len(value) > DNS1123SubdomainMaxLength {
|
||||
errs = append(errs, MaxLenError(DNS1123SubdomainMaxLength))
|
||||
}
|
||||
if !dns1123SubdomainRegexp.MatchString(value) {
|
||||
errs = append(errs, RegexError(dns1123SubdomainErrorMsg, dns1123SubdomainFmt, "example.com"))
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
const dns1035LabelFmt string = "[a-z]([-a-z0-9]*[a-z0-9])?"
|
||||
const dns1035LabelErrMsg string = "a DNS-1035 label must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character"
|
||||
|
||||
// DNS1035LabelMaxLength is a label's max length in DNS (RFC 1035)
|
||||
const DNS1035LabelMaxLength int = 63
|
||||
|
||||
var dns1035LabelRegexp = regexp.MustCompile("^" + dns1035LabelFmt + "$")
|
||||
|
||||
// IsDNS1035Label tests for a string that conforms to the definition of a label in
|
||||
// DNS (RFC 1035).
|
||||
func IsDNS1035Label(value string) []string {
|
||||
var errs []string
|
||||
if len(value) > DNS1035LabelMaxLength {
|
||||
errs = append(errs, MaxLenError(DNS1035LabelMaxLength))
|
||||
}
|
||||
if !dns1035LabelRegexp.MatchString(value) {
|
||||
errs = append(errs, RegexError(dns1035LabelErrMsg, dns1035LabelFmt, "my-name", "abc-123"))
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
// wildcard definition - RFC 1034 section 4.3.3.
|
||||
// examples:
|
||||
// - valid: *.bar.com, *.foo.bar.com
|
||||
// - invalid: *.*.bar.com, *.foo.*.com, *bar.com, f*.bar.com, *
|
||||
const wildcardDNS1123SubdomainFmt = "\\*\\." + dns1123SubdomainFmt
|
||||
const wildcardDNS1123SubdomainErrMsg = "a wildcard DNS-1123 subdomain must start with '*.', followed by a valid DNS subdomain, which must consist of lower case alphanumeric characters, '-' or '.' and end with an alphanumeric character"
|
||||
|
||||
// IsWildcardDNS1123Subdomain tests for a string that conforms to the definition of a
|
||||
// wildcard subdomain in DNS (RFC 1034 section 4.3.3).
|
||||
func IsWildcardDNS1123Subdomain(value string) []string {
|
||||
wildcardDNS1123SubdomainRegexp := regexp.MustCompile("^" + wildcardDNS1123SubdomainFmt + "$")
|
||||
|
||||
var errs []string
|
||||
if len(value) > DNS1123SubdomainMaxLength {
|
||||
errs = append(errs, MaxLenError(DNS1123SubdomainMaxLength))
|
||||
}
|
||||
if !wildcardDNS1123SubdomainRegexp.MatchString(value) {
|
||||
errs = append(errs, RegexError(wildcardDNS1123SubdomainErrMsg, wildcardDNS1123SubdomainFmt, "*.example.com"))
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
const cIdentifierFmt string = "[A-Za-z_][A-Za-z0-9_]*"
|
||||
const identifierErrMsg string = "a valid C identifier must start with alphabetic character or '_', followed by a string of alphanumeric characters or '_'"
|
||||
|
||||
var cIdentifierRegexp = regexp.MustCompile("^" + cIdentifierFmt + "$")
|
||||
|
||||
// IsCIdentifier tests for a string that conforms the definition of an identifier
|
||||
// in C. This checks the format, but not the length.
|
||||
func IsCIdentifier(value string) []string {
|
||||
if !cIdentifierRegexp.MatchString(value) {
|
||||
return []string{RegexError(identifierErrMsg, cIdentifierFmt, "my_name", "MY_NAME", "MyName")}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValidPortNum tests that the argument is a valid, non-zero port number.
|
||||
func IsValidPortNum(port int) []string {
|
||||
if 1 <= port && port <= 65535 {
|
||||
return nil
|
||||
}
|
||||
return []string{InclusiveRangeError(1, 65535)}
|
||||
}
|
||||
|
||||
// IsInRange tests that the argument is in an inclusive range.
|
||||
func IsInRange(value int, min int, max int) []string {
|
||||
if value >= min && value <= max {
|
||||
return nil
|
||||
}
|
||||
return []string{InclusiveRangeError(min, max)}
|
||||
}
|
||||
|
||||
// Now in libcontainer UID/GID limits is 0 ~ 1<<31 - 1
|
||||
// TODO: once we have a type for UID/GID we should make these that type.
|
||||
const (
|
||||
minUserID = 0
|
||||
maxUserID = math.MaxInt32
|
||||
minGroupID = 0
|
||||
maxGroupID = math.MaxInt32
|
||||
)
|
||||
|
||||
// IsValidGroupID tests that the argument is a valid Unix GID.
|
||||
func IsValidGroupID(gid int64) []string {
|
||||
if minGroupID <= gid && gid <= maxGroupID {
|
||||
return nil
|
||||
}
|
||||
return []string{InclusiveRangeError(minGroupID, maxGroupID)}
|
||||
}
|
||||
|
||||
// IsValidUserID tests that the argument is a valid Unix UID.
|
||||
func IsValidUserID(uid int64) []string {
|
||||
if minUserID <= uid && uid <= maxUserID {
|
||||
return nil
|
||||
}
|
||||
return []string{InclusiveRangeError(minUserID, maxUserID)}
|
||||
}
|
||||
|
||||
var portNameCharsetRegex = regexp.MustCompile("^[-a-z0-9]+$")
|
||||
var portNameOneLetterRegexp = regexp.MustCompile("[a-z]")
|
||||
|
||||
// IsValidPortName check that the argument is valid syntax. It must be
|
||||
// non-empty and no more than 15 characters long. It may contain only [-a-z0-9]
|
||||
// and must contain at least one letter [a-z]. It must not start or end with a
|
||||
// hyphen, nor contain adjacent hyphens.
|
||||
//
|
||||
// Note: We only allow lower-case characters, even though RFC 6335 is case
|
||||
// insensitive.
|
||||
func IsValidPortName(port string) []string {
|
||||
var errs []string
|
||||
if len(port) > 15 {
|
||||
errs = append(errs, MaxLenError(15))
|
||||
}
|
||||
if !portNameCharsetRegex.MatchString(port) {
|
||||
errs = append(errs, "must contain only alpha-numeric characters (a-z, 0-9), and hyphens (-)")
|
||||
}
|
||||
if !portNameOneLetterRegexp.MatchString(port) {
|
||||
errs = append(errs, "must contain at least one letter or number (a-z, 0-9)")
|
||||
}
|
||||
if strings.Contains(port, "--") {
|
||||
errs = append(errs, "must not contain consecutive hyphens")
|
||||
}
|
||||
if len(port) > 0 && (port[0] == '-' || port[len(port)-1] == '-') {
|
||||
errs = append(errs, "must not begin or end with a hyphen")
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
// IsValidIP tests that the argument is a valid IP address.
|
||||
func IsValidIP(value string) []string {
|
||||
if net.ParseIP(value) == nil {
|
||||
return []string{"must be a valid IP address, (e.g. 10.9.8.7)"}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValidIPv4Address tests that the argument is a valid IPv4 address.
|
||||
func IsValidIPv4Address(fldPath *field.Path, value string) field.ErrorList {
|
||||
var allErrors field.ErrorList
|
||||
ip := net.ParseIP(value)
|
||||
if ip == nil || ip.To4() == nil {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid IPv4 address"))
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
// IsValidIPv6Address tests that the argument is a valid IPv6 address.
|
||||
func IsValidIPv6Address(fldPath *field.Path, value string) field.ErrorList {
|
||||
var allErrors field.ErrorList
|
||||
ip := net.ParseIP(value)
|
||||
if ip == nil || ip.To4() != nil {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid IPv6 address"))
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
const percentFmt string = "[0-9]+%"
|
||||
const percentErrMsg string = "a valid percent string must be a numeric string followed by an ending '%'"
|
||||
|
||||
var percentRegexp = regexp.MustCompile("^" + percentFmt + "$")
|
||||
|
||||
// IsValidPercent checks that string is in the form of a percentage
|
||||
func IsValidPercent(percent string) []string {
|
||||
if !percentRegexp.MatchString(percent) {
|
||||
return []string{RegexError(percentErrMsg, percentFmt, "1%", "93%")}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
const httpHeaderNameFmt string = "[-A-Za-z0-9]+"
|
||||
const httpHeaderNameErrMsg string = "a valid HTTP header must consist of alphanumeric characters or '-'"
|
||||
|
||||
var httpHeaderNameRegexp = regexp.MustCompile("^" + httpHeaderNameFmt + "$")
|
||||
|
||||
// IsHTTPHeaderName checks that a string conforms to the Go HTTP library's
|
||||
// definition of a valid header field name (a stricter subset than RFC7230).
|
||||
func IsHTTPHeaderName(value string) []string {
|
||||
if !httpHeaderNameRegexp.MatchString(value) {
|
||||
return []string{RegexError(httpHeaderNameErrMsg, httpHeaderNameFmt, "X-Header-Name")}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
const envVarNameFmt = "[-._a-zA-Z][-._a-zA-Z0-9]*"
|
||||
const envVarNameFmtErrMsg string = "a valid environment variable name must consist of alphabetic characters, digits, '_', '-', or '.', and must not start with a digit"
|
||||
|
||||
var envVarNameRegexp = regexp.MustCompile("^" + envVarNameFmt + "$")
|
||||
|
||||
// IsEnvVarName tests if a string is a valid environment variable name.
|
||||
func IsEnvVarName(value string) []string {
|
||||
var errs []string
|
||||
if !envVarNameRegexp.MatchString(value) {
|
||||
errs = append(errs, RegexError(envVarNameFmtErrMsg, envVarNameFmt, "my.env-name", "MY_ENV.NAME", "MyEnvName1"))
|
||||
}
|
||||
|
||||
errs = append(errs, hasChDirPrefix(value)...)
|
||||
return errs
|
||||
}
|
||||
|
||||
const configMapKeyFmt = `[-._a-zA-Z0-9]+`
|
||||
const configMapKeyErrMsg string = "a valid config key must consist of alphanumeric characters, '-', '_' or '.'"
|
||||
|
||||
var configMapKeyRegexp = regexp.MustCompile("^" + configMapKeyFmt + "$")
|
||||
|
||||
// IsConfigMapKey tests for a string that is a valid key for a ConfigMap or Secret
|
||||
func IsConfigMapKey(value string) []string {
|
||||
var errs []string
|
||||
if len(value) > DNS1123SubdomainMaxLength {
|
||||
errs = append(errs, MaxLenError(DNS1123SubdomainMaxLength))
|
||||
}
|
||||
if !configMapKeyRegexp.MatchString(value) {
|
||||
errs = append(errs, RegexError(configMapKeyErrMsg, configMapKeyFmt, "key.name", "KEY_NAME", "key-name"))
|
||||
}
|
||||
errs = append(errs, hasChDirPrefix(value)...)
|
||||
return errs
|
||||
}
|
||||
|
||||
// MaxLenError returns a string explanation of a "string too long" validation
|
||||
// failure.
|
||||
func MaxLenError(length int) string {
|
||||
return fmt.Sprintf("must be no more than %d characters", length)
|
||||
}
|
||||
|
||||
// RegexError returns a string explanation of a regex validation failure.
|
||||
func RegexError(msg string, fmt string, examples ...string) string {
|
||||
if len(examples) == 0 {
|
||||
return msg + " (regex used for validation is '" + fmt + "')"
|
||||
}
|
||||
msg += " (e.g. "
|
||||
for i := range examples {
|
||||
if i > 0 {
|
||||
msg += " or "
|
||||
}
|
||||
msg += "'" + examples[i] + "', "
|
||||
}
|
||||
msg += "regex used for validation is '" + fmt + "')"
|
||||
return msg
|
||||
}
|
||||
|
||||
// EmptyError returns a string explanation of a "must not be empty" validation
|
||||
// failure.
|
||||
func EmptyError() string {
|
||||
return "must be non-empty"
|
||||
}
|
||||
|
||||
func prefixEach(msgs []string, prefix string) []string {
|
||||
for i := range msgs {
|
||||
msgs[i] = prefix + msgs[i]
|
||||
}
|
||||
return msgs
|
||||
}
|
||||
|
||||
// InclusiveRangeError returns a string explanation of a numeric "must be
|
||||
// between" validation failure.
|
||||
func InclusiveRangeError(lo, hi int) string {
|
||||
return fmt.Sprintf(`must be between %d and %d, inclusive`, lo, hi)
|
||||
}
|
||||
|
||||
func hasChDirPrefix(value string) []string {
|
||||
var errs []string
|
||||
switch {
|
||||
case value == ".":
|
||||
errs = append(errs, `must not be '.'`)
|
||||
case value == "..":
|
||||
errs = append(errs, `must not be '..'`)
|
||||
case strings.HasPrefix(value, ".."):
|
||||
errs = append(errs, `must not start with '..'`)
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
// IsValidSocketAddr checks that string represents a valid socket address
|
||||
// as defined in RFC 789. (e.g 0.0.0.0:10254 or [::]:10254))
|
||||
func IsValidSocketAddr(value string) []string {
|
||||
var errs []string
|
||||
ip, port, err := net.SplitHostPort(value)
|
||||
if err != nil {
|
||||
errs = append(errs, "must be a valid socket address format, (e.g. 0.0.0.0:10254 or [::]:10254)")
|
||||
return errs
|
||||
}
|
||||
portInt, _ := strconv.Atoi(port)
|
||||
errs = append(errs, IsValidPortNum(portInt)...)
|
||||
errs = append(errs, IsValidIP(ip)...)
|
||||
return errs
|
||||
}
|
||||
137
vendor/sigs.k8s.io/kustomize/kyaml/yaml/kfns.go
generated
vendored
Normal file
137
vendor/sigs.k8s.io/kustomize/kyaml/yaml/kfns.go
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"gopkg.in/yaml.v3"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
)
|
||||
|
||||
// AnnotationClearer removes an annotation at metadata.annotations.
|
||||
// Returns nil if the annotation or field does not exist.
|
||||
type AnnotationClearer struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
Key string `yaml:"key,omitempty"`
|
||||
}
|
||||
|
||||
func (c AnnotationClearer) Filter(rn *RNode) (*RNode, error) {
|
||||
return rn.Pipe(
|
||||
PathGetter{Path: []string{MetadataField, AnnotationsField}},
|
||||
FieldClearer{Name: c.Key})
|
||||
}
|
||||
|
||||
func ClearAnnotation(key string) AnnotationClearer {
|
||||
return AnnotationClearer{Key: key}
|
||||
}
|
||||
|
||||
// ClearEmptyAnnotations clears the keys, annotations
|
||||
// and metadata if they are empty/null
|
||||
func ClearEmptyAnnotations(rn *RNode) error {
|
||||
_, err := rn.Pipe(Lookup(MetadataField), FieldClearer{
|
||||
Name: AnnotationsField, IfEmpty: true})
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
_, err = rn.Pipe(FieldClearer{Name: MetadataField, IfEmpty: true})
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// k8sMetaSetter sets a name at metadata.{key}.
|
||||
// Creates metadata if does not exist.
|
||||
type k8sMetaSetter struct {
|
||||
Key string `yaml:"key,omitempty"`
|
||||
Value string `yaml:"value,omitempty"`
|
||||
}
|
||||
|
||||
func (s k8sMetaSetter) Filter(rn *RNode) (*RNode, error) {
|
||||
_, err := rn.Pipe(
|
||||
PathGetter{Path: []string{MetadataField}, Create: yaml.MappingNode},
|
||||
FieldSetter{Name: s.Key, Value: NewStringRNode(s.Value)})
|
||||
return rn, err
|
||||
}
|
||||
|
||||
func SetK8sName(value string) k8sMetaSetter {
|
||||
return k8sMetaSetter{Key: NameField, Value: value}
|
||||
}
|
||||
|
||||
func SetK8sNamespace(value string) k8sMetaSetter {
|
||||
return k8sMetaSetter{Key: NamespaceField, Value: value}
|
||||
}
|
||||
|
||||
// AnnotationSetter sets an annotation at metadata.annotations.
|
||||
// Creates metadata.annotations if does not exist.
|
||||
type AnnotationSetter struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
Key string `yaml:"key,omitempty"`
|
||||
Value string `yaml:"value,omitempty"`
|
||||
}
|
||||
|
||||
func (s AnnotationSetter) Filter(rn *RNode) (*RNode, error) {
|
||||
v := NewStringRNode(s.Value)
|
||||
// some tools get confused about the type if annotations are not quoted
|
||||
v.YNode().Style = yaml.SingleQuotedStyle
|
||||
if err := ClearEmptyAnnotations(rn); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return addMetadataNode(rn, AnnotationsField, s.Key, v)
|
||||
}
|
||||
|
||||
func SetAnnotation(key, value string) AnnotationSetter {
|
||||
return AnnotationSetter{Key: key, Value: value}
|
||||
}
|
||||
|
||||
// AnnotationGetter gets an annotation at metadata.annotations.
|
||||
// Returns nil if metadata.annotations does not exist.
|
||||
type AnnotationGetter struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
Key string `yaml:"key,omitempty"`
|
||||
Value string `yaml:"value,omitempty"`
|
||||
}
|
||||
|
||||
// AnnotationGetter returns the annotation value.
|
||||
// Returns "", nil if the annotation does not exist.
|
||||
func (g AnnotationGetter) Filter(rn *RNode) (*RNode, error) {
|
||||
v, err := rn.Pipe(
|
||||
PathGetter{Path: []string{MetadataField, AnnotationsField, g.Key}})
|
||||
if v == nil || err != nil {
|
||||
return v, err
|
||||
}
|
||||
if g.Value == "" || v.value.Value == g.Value {
|
||||
return v, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func GetAnnotation(key string) AnnotationGetter {
|
||||
return AnnotationGetter{Key: key}
|
||||
}
|
||||
|
||||
// LabelSetter sets a label at metadata.labels.
|
||||
// Creates metadata.labels if does not exist.
|
||||
type LabelSetter struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
Key string `yaml:"key,omitempty"`
|
||||
Value string `yaml:"value,omitempty"`
|
||||
}
|
||||
|
||||
func (s LabelSetter) Filter(rn *RNode) (*RNode, error) {
|
||||
v := NewStringRNode(s.Value)
|
||||
// some tools get confused about the type if labels are not quoted
|
||||
v.YNode().Style = yaml.SingleQuotedStyle
|
||||
return addMetadataNode(rn, LabelsField, s.Key, v)
|
||||
}
|
||||
|
||||
func addMetadataNode(rn *RNode, field, key string, v *RNode) (*RNode, error) {
|
||||
return rn.Pipe(
|
||||
PathGetter{
|
||||
Path: []string{MetadataField, field}, Create: yaml.MappingNode},
|
||||
FieldSetter{Name: key, Value: v})
|
||||
}
|
||||
|
||||
func SetLabel(key, value string) LabelSetter {
|
||||
return LabelSetter{Key: key, Value: value}
|
||||
}
|
||||
40
vendor/sigs.k8s.io/kustomize/kyaml/yaml/mapnode.go
generated
vendored
Normal file
40
vendor/sigs.k8s.io/kustomize/kyaml/yaml/mapnode.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
// MapNode wraps a field key and value.
|
||||
type MapNode struct {
|
||||
Key *RNode
|
||||
Value *RNode
|
||||
}
|
||||
|
||||
// IsNilOrEmpty returns true if the MapNode is nil,
|
||||
// has no value, or has a value that appears empty.
|
||||
func (mn *MapNode) IsNilOrEmpty() bool {
|
||||
return mn == nil || mn.Value.IsNilOrEmpty()
|
||||
}
|
||||
|
||||
type MapNodeSlice []*MapNode
|
||||
|
||||
func (m MapNodeSlice) Keys() []*RNode {
|
||||
var keys []*RNode
|
||||
for i := range m {
|
||||
if m[i] != nil {
|
||||
keys = append(keys, m[i].Key)
|
||||
}
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
func (m MapNodeSlice) Values() []*RNode {
|
||||
var values []*RNode
|
||||
for i := range m {
|
||||
if m[i] != nil {
|
||||
values = append(values, m[i].Value)
|
||||
} else {
|
||||
values = append(values, nil)
|
||||
}
|
||||
}
|
||||
return values
|
||||
}
|
||||
206
vendor/sigs.k8s.io/kustomize/kyaml/yaml/match.go
generated
vendored
Normal file
206
vendor/sigs.k8s.io/kustomize/kyaml/yaml/match.go
generated
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// PathMatcher returns all RNodes matching the path wrapped in a SequenceNode.
|
||||
// Lists may have multiple elements matching the path, and each matching element
|
||||
// is added to the return result.
|
||||
// If Path points to a SequenceNode, the SequenceNode is wrapped in another SequenceNode
|
||||
// If Path does not contain any lists, the result is still wrapped in a SequenceNode of len == 1
|
||||
type PathMatcher struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
|
||||
// Path is a slice of parts leading to the RNode to lookup.
|
||||
// Each path part may be one of:
|
||||
// * FieldMatcher -- e.g. "spec"
|
||||
// * Map Key -- e.g. "app.k8s.io/version"
|
||||
// * List Entry -- e.g. "[name=nginx]" or "[=-jar]"
|
||||
//
|
||||
// Map Keys and Fields are equivalent.
|
||||
// See FieldMatcher for more on Fields and Map Keys.
|
||||
//
|
||||
// List Entries are specified as map entry to match [fieldName=fieldValue].
|
||||
// See Elem for more on List Entries.
|
||||
//
|
||||
// Examples:
|
||||
// * spec.template.spec.container with matching name: [name=nginx] -- match 'name': 'nginx'
|
||||
// * spec.template.spec.container.argument matching a value: [=-jar] -- match '-jar'
|
||||
Path []string `yaml:"path,omitempty"`
|
||||
|
||||
// Matches is set by PathMatch to publish the matched element values for each node.
|
||||
// After running PathMatcher.Filter, each node from the SequenceNode result may be
|
||||
// looked up in Matches to find the field values that were matched.
|
||||
Matches map[*Node][]string
|
||||
|
||||
// StripComments may be set to remove the comments on the matching Nodes.
|
||||
// This is useful for if the nodes are to be printed in FlowStyle.
|
||||
StripComments bool
|
||||
|
||||
val *RNode
|
||||
field string
|
||||
matchRegex string
|
||||
}
|
||||
|
||||
func (p *PathMatcher) stripComments(n *Node) {
|
||||
if n == nil {
|
||||
return
|
||||
}
|
||||
if p.StripComments {
|
||||
n.LineComment = ""
|
||||
n.HeadComment = ""
|
||||
n.FootComment = ""
|
||||
for i := range n.Content {
|
||||
p.stripComments(n.Content[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PathMatcher) Filter(rn *RNode) (*RNode, error) {
|
||||
val, err := p.filter(rn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.stripComments(val.YNode())
|
||||
return val, err
|
||||
}
|
||||
|
||||
func (p *PathMatcher) filter(rn *RNode) (*RNode, error) {
|
||||
p.Matches = map[*Node][]string{}
|
||||
|
||||
if len(p.Path) == 0 {
|
||||
// return the element wrapped in a SequenceNode
|
||||
p.appendRNode("", rn)
|
||||
return p.val, nil
|
||||
}
|
||||
|
||||
if IsListIndex(p.Path[0]) {
|
||||
// match seq elements
|
||||
return p.doSeq(rn)
|
||||
}
|
||||
// match a field
|
||||
return p.doField(rn)
|
||||
}
|
||||
|
||||
func (p *PathMatcher) doField(rn *RNode) (*RNode, error) {
|
||||
// lookup the field
|
||||
field, err := rn.Pipe(Get(p.Path[0]))
|
||||
if err != nil || field == nil {
|
||||
// if the field doesn't exist, return nil
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// recurse on the field, removing the first element of the path
|
||||
pm := &PathMatcher{Path: p.Path[1:]}
|
||||
p.val, err = pm.filter(field)
|
||||
p.Matches = pm.Matches
|
||||
return p.val, err
|
||||
}
|
||||
|
||||
// doSeq iterates over a sequence and appends elements matching the path regex to p.Val
|
||||
func (p *PathMatcher) doSeq(rn *RNode) (*RNode, error) {
|
||||
// parse the field + match pair
|
||||
var err error
|
||||
p.field, p.matchRegex, err = SplitIndexNameValue(p.Path[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if p.field == "" {
|
||||
err = rn.VisitElements(p.visitPrimitiveElem)
|
||||
} else {
|
||||
err = rn.VisitElements(p.visitElem)
|
||||
}
|
||||
if err != nil || p.val == nil || len(p.val.YNode().Content) == 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return p.val, nil
|
||||
}
|
||||
|
||||
func (p *PathMatcher) visitPrimitiveElem(elem *RNode) error {
|
||||
r, err := regexp.Compile(p.matchRegex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
str, err := elem.String()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
str = strings.TrimSpace(str)
|
||||
if !r.MatchString(str) {
|
||||
return nil
|
||||
}
|
||||
|
||||
p.appendRNode("", elem)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PathMatcher) visitElem(elem *RNode) error {
|
||||
r, err := regexp.Compile(p.matchRegex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if this elements field matches the regex
|
||||
val := elem.Field(p.field)
|
||||
if val == nil || val.Value == nil {
|
||||
return nil
|
||||
}
|
||||
str, err := val.Value.String()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
str = strings.TrimSpace(str)
|
||||
if !r.MatchString(str) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// recurse on the matching element
|
||||
pm := &PathMatcher{Path: p.Path[1:]}
|
||||
add, err := pm.filter(elem)
|
||||
for k, v := range pm.Matches {
|
||||
p.Matches[k] = v
|
||||
}
|
||||
if err != nil || add == nil {
|
||||
return err
|
||||
}
|
||||
p.append(str, add.Content()...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PathMatcher) appendRNode(path string, node *RNode) {
|
||||
p.append(path, node.YNode())
|
||||
}
|
||||
|
||||
func (p *PathMatcher) append(path string, nodes ...*Node) {
|
||||
if p.val == nil {
|
||||
p.val = NewRNode(&Node{Kind: SequenceNode})
|
||||
}
|
||||
for i := range nodes {
|
||||
node := nodes[i]
|
||||
p.val.YNode().Content = append(p.val.YNode().Content, node)
|
||||
// record the path if specified
|
||||
if path != "" {
|
||||
p.Matches[node] = append(p.Matches[node], path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func cleanPath(path []string) []string {
|
||||
var p []string
|
||||
for _, elem := range path {
|
||||
elem = strings.TrimSpace(elem)
|
||||
if len(elem) == 0 {
|
||||
continue
|
||||
}
|
||||
p = append(p, elem)
|
||||
}
|
||||
return p
|
||||
}
|
||||
107
vendor/sigs.k8s.io/kustomize/kyaml/yaml/order.go
generated
vendored
Normal file
107
vendor/sigs.k8s.io/kustomize/kyaml/yaml/order.go
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
// fieldSortOrder contains the relative ordering of fields when formatting an
|
||||
// object.
|
||||
var fieldSortOrder = []string{
|
||||
// top-level metadata
|
||||
"name", "generateName", "namespace", "clusterName",
|
||||
"apiVersion", "kind", "metadata", "type",
|
||||
"labels", "annotations",
|
||||
"spec", "status",
|
||||
|
||||
// secret and configmap
|
||||
"stringData", "data", "binaryData",
|
||||
|
||||
// cronjobspec, daemonsetspec, deploymentspec, statefulsetspec,
|
||||
// jobspec fields
|
||||
"parallelism", "completions", "activeDeadlineSeconds", "backoffLimit",
|
||||
"replicas", "selector", "manualSelector", "template",
|
||||
"ttlSecondsAfterFinished", "volumeClaimTemplates", "service", "serviceName",
|
||||
"podManagementPolicy", "updateStrategy", "strategy", "minReadySeconds",
|
||||
"revision", "revisionHistoryLimit", "paused", "progressDeadlineSeconds",
|
||||
|
||||
// podspec
|
||||
// podspec scalars
|
||||
"restartPolicy", "terminationGracePeriodSeconds",
|
||||
"activeDeadlineSeconds", "dnsPolicy", "serviceAccountName",
|
||||
"serviceAccount", "automountServiceAccountToken", "nodeName",
|
||||
"hostNetwork", "hostPID", "hostIPC", "shareProcessNamespace", "hostname",
|
||||
"subdomain", "schedulerName", "priorityClassName", "priority",
|
||||
"runtimeClassName", "enableServiceLinks",
|
||||
|
||||
// podspec lists and maps
|
||||
"nodeSelector", "hostAliases",
|
||||
|
||||
// podspec objects
|
||||
"initContainers", "containers", "volumes", "securityContext",
|
||||
"imagePullSecrets", "affinity", "tolerations", "dnsConfig",
|
||||
"readinessGates",
|
||||
|
||||
// containers
|
||||
"image", "command", "args", "workingDir", "ports", "envFrom", "env",
|
||||
"resources", "volumeMounts", "volumeDevices", "livenessProbe",
|
||||
"readinessProbe", "lifecycle", "terminationMessagePath",
|
||||
"terminationMessagePolicy", "imagePullPolicy", "securityContext",
|
||||
"stdin", "stdinOnce", "tty",
|
||||
|
||||
// service
|
||||
"clusterIP", "externalIPs", "loadBalancerIP", "loadBalancerSourceRanges",
|
||||
"externalName", "externalTrafficPolicy", "sessionAffinity",
|
||||
|
||||
// ports
|
||||
"protocol", "port", "targetPort", "hostPort", "containerPort", "hostIP",
|
||||
|
||||
// volumemount
|
||||
"readOnly", "mountPath", "subPath", "subPathExpr", "mountPropagation",
|
||||
|
||||
// envvar + envvarsource
|
||||
"value", "valueFrom", "fieldRef", "resourceFieldRef", "configMapKeyRef",
|
||||
"secretKeyRef", "prefix", "configMapRef", "secretRef",
|
||||
}
|
||||
|
||||
type set map[string]interface{}
|
||||
|
||||
func newSet(values ...string) set {
|
||||
m := map[string]interface{}{}
|
||||
for _, value := range values {
|
||||
m[value] = nil
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (s set) Has(key string) bool {
|
||||
_, found := s[key]
|
||||
return found
|
||||
}
|
||||
|
||||
// WhitelistedListSortKinds contains the set of kinds that are whitelisted
|
||||
// for sorting list field elements
|
||||
var WhitelistedListSortKinds = newSet(
|
||||
"CronJob", "DaemonSet", "Deployment", "Job", "ReplicaSet", "StatefulSet",
|
||||
"ValidatingWebhookConfiguration")
|
||||
|
||||
// WhitelistedListSortApis contains the set of apis that are whitelisted for
|
||||
// sorting list field elements
|
||||
var WhitelistedListSortApis = newSet(
|
||||
"apps/v1", "apps/v1beta1", "apps/v1beta2", "batch/v1", "batch/v1beta1",
|
||||
"extensions/v1beta1", "v1", "admissionregistration.k8s.io/v1")
|
||||
|
||||
// WhitelistedListSortFields contains json paths to list fields that should
|
||||
// be sorted, and the field they should be sorted by
|
||||
var WhitelistedListSortFields = map[string]string{
|
||||
".spec.template.spec.containers": "name",
|
||||
".webhooks.rules.operations": "",
|
||||
}
|
||||
|
||||
// FieldOrder indexes fields and maps them to relative precedence
|
||||
var FieldOrder = func() map[string]int {
|
||||
// create an index of field orderings
|
||||
fo := map[string]int{}
|
||||
for i, f := range fieldSortOrder {
|
||||
fo[f] = i + 1
|
||||
}
|
||||
return fo
|
||||
}()
|
||||
1008
vendor/sigs.k8s.io/kustomize/kyaml/yaml/rnode.go
generated
vendored
Normal file
1008
vendor/sigs.k8s.io/kustomize/kyaml/yaml/rnode.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
76
vendor/sigs.k8s.io/kustomize/kyaml/yaml/serialization.go
generated
vendored
Normal file
76
vendor/sigs.k8s.io/kustomize/kyaml/yaml/serialization.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
import "gopkg.in/yaml.v3"
|
||||
|
||||
func DoSerializationHacksOnNodes(nodes []*RNode) {
|
||||
for _, node := range nodes {
|
||||
DoSerializationHacks(node.YNode())
|
||||
}
|
||||
}
|
||||
|
||||
// DoSerializationHacks addresses a bug in yaml V3 upstream, it parses the yaml node,
|
||||
// and rearranges the head comments of the children of sequence node.
|
||||
// Refer to https://github.com/go-yaml/yaml/issues/587 for more details
|
||||
func DoSerializationHacks(node *yaml.Node) {
|
||||
switch node.Kind {
|
||||
case DocumentNode:
|
||||
for _, node := range node.Content {
|
||||
DoSerializationHacks(node)
|
||||
}
|
||||
|
||||
case MappingNode:
|
||||
for _, node := range node.Content {
|
||||
DoSerializationHacks(node)
|
||||
}
|
||||
|
||||
case SequenceNode:
|
||||
for _, node := range node.Content {
|
||||
// for each child mapping node, transfer the head comment of it's
|
||||
// first child scalar node to the head comment of itself
|
||||
// This is necessary to address serialization issue
|
||||
// https://github.com/go-yaml/yaml/issues/587 in go-yaml.v3
|
||||
// Remove this hack when the issue has been resolved
|
||||
if len(node.Content) > 0 && node.Content[0].Kind == ScalarNode {
|
||||
node.HeadComment = node.Content[0].HeadComment
|
||||
node.Content[0].HeadComment = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func UndoSerializationHacksOnNodes(nodes []*RNode) {
|
||||
for _, node := range nodes {
|
||||
UndoSerializationHacks(node.YNode())
|
||||
}
|
||||
}
|
||||
|
||||
// UndoSerializationHacks reverts the changes made by DoSerializationHacks
|
||||
// Refer to https://github.com/go-yaml/yaml/issues/587 for more details
|
||||
func UndoSerializationHacks(node *yaml.Node) {
|
||||
switch node.Kind {
|
||||
case DocumentNode:
|
||||
for _, node := range node.Content {
|
||||
DoSerializationHacks(node)
|
||||
}
|
||||
|
||||
case MappingNode:
|
||||
for _, node := range node.Content {
|
||||
DoSerializationHacks(node)
|
||||
}
|
||||
|
||||
case SequenceNode:
|
||||
for _, node := range node.Content {
|
||||
// revert the changes made in DoSerializationHacks
|
||||
// This is necessary to address serialization issue
|
||||
// https://github.com/go-yaml/yaml/issues/587 in go-yaml.v3
|
||||
// Remove this hack when the issue has been resolved
|
||||
if len(node.Content) > 0 && node.Content[0].Kind == ScalarNode {
|
||||
node.Content[0].HeadComment = node.HeadComment
|
||||
node.HeadComment = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
237
vendor/sigs.k8s.io/kustomize/kyaml/yaml/types.go
generated
vendored
Normal file
237
vendor/sigs.k8s.io/kustomize/kyaml/yaml/types.go
generated
vendored
Normal file
@@ -0,0 +1,237 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/sets"
|
||||
)
|
||||
|
||||
// CopyYNode returns a distinct copy of its argument.
|
||||
// Use https://github.com/jinzhu/copier instead?
|
||||
func CopyYNode(n *yaml.Node) *yaml.Node {
|
||||
if n == nil {
|
||||
return nil
|
||||
}
|
||||
c := *n
|
||||
if len(n.Content) > 0 {
|
||||
// Using Go 'copy' here doesn't yield independent slices.
|
||||
c.Content = make([]*Node, len(n.Content))
|
||||
for i, item := range n.Content {
|
||||
c.Content[i] = CopyYNode(item)
|
||||
}
|
||||
}
|
||||
return &c
|
||||
}
|
||||
|
||||
// IsYNodeTaggedNull returns true if the node is explicitly tagged Null.
|
||||
func IsYNodeTaggedNull(n *yaml.Node) bool {
|
||||
return n != nil && n.Tag == NodeTagNull
|
||||
}
|
||||
|
||||
// IsYNodeEmptyMap is true if the Node is a non-nil empty map.
|
||||
func IsYNodeEmptyMap(n *yaml.Node) bool {
|
||||
return n != nil && n.Kind == yaml.MappingNode && len(n.Content) == 0
|
||||
}
|
||||
|
||||
// IsYNodeEmptyMap is true if the Node is a non-nil empty sequence.
|
||||
func IsYNodeEmptySeq(n *yaml.Node) bool {
|
||||
return n != nil && n.Kind == yaml.SequenceNode && len(n.Content) == 0
|
||||
}
|
||||
|
||||
// IsYNodeEmptyDoc is true if the node is a Document with no content.
|
||||
// E.g.: "---\n---"
|
||||
func IsYNodeEmptyDoc(n *yaml.Node) bool {
|
||||
return n.Kind == yaml.DocumentNode && n.Content[0].Tag == NodeTagNull
|
||||
}
|
||||
|
||||
func IsYNodeString(n *yaml.Node) bool {
|
||||
return n.Kind == yaml.ScalarNode &&
|
||||
(n.Tag == NodeTagString || n.Tag == NodeTagEmpty)
|
||||
}
|
||||
|
||||
// IsYNodeZero is true if all the public fields in the Node are empty.
|
||||
// Which means it's not initialized and should be omitted when marshal.
|
||||
// The Node itself has a method IsZero but it is not released
|
||||
// in yaml.v3. https://pkg.go.dev/gopkg.in/yaml.v3#Node.IsZero
|
||||
func IsYNodeZero(n *yaml.Node) bool {
|
||||
// TODO: Change this to use IsZero when it's avaialable.
|
||||
return n != nil && n.Kind == 0 && n.Style == 0 && n.Tag == "" && n.Value == "" &&
|
||||
n.Anchor == "" && n.Alias == nil && n.Content == nil &&
|
||||
n.HeadComment == "" && n.LineComment == "" && n.FootComment == "" &&
|
||||
n.Line == 0 && n.Column == 0
|
||||
}
|
||||
|
||||
// Parser parses values into configuration.
|
||||
type Parser struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
Value string `yaml:"value,omitempty"`
|
||||
}
|
||||
|
||||
func (p Parser) Filter(_ *RNode) (*RNode, error) {
|
||||
d := yaml.NewDecoder(bytes.NewBuffer([]byte(p.Value)))
|
||||
o := &RNode{value: &yaml.Node{}}
|
||||
return o, d.Decode(o.value)
|
||||
}
|
||||
|
||||
// TODO(pwittrock): test this
|
||||
func GetStyle(styles ...string) Style {
|
||||
var style Style
|
||||
for _, s := range styles {
|
||||
switch s {
|
||||
case "TaggedStyle":
|
||||
style |= TaggedStyle
|
||||
case "DoubleQuotedStyle":
|
||||
style |= DoubleQuotedStyle
|
||||
case "SingleQuotedStyle":
|
||||
style |= SingleQuotedStyle
|
||||
case "LiteralStyle":
|
||||
style |= LiteralStyle
|
||||
case "FoldedStyle":
|
||||
style |= FoldedStyle
|
||||
case "FlowStyle":
|
||||
style |= FlowStyle
|
||||
}
|
||||
}
|
||||
return style
|
||||
}
|
||||
|
||||
// Filter defines a function to manipulate an individual RNode such as by changing
|
||||
// its values, or returning a field.
|
||||
//
|
||||
// When possible, Filters should be serializable to yaml so that they can be described
|
||||
// declaratively as data.
|
||||
//
|
||||
// Analogous to http://www.linfo.org/filters.html
|
||||
type Filter interface {
|
||||
Filter(object *RNode) (*RNode, error)
|
||||
}
|
||||
|
||||
type FilterFunc func(object *RNode) (*RNode, error)
|
||||
|
||||
func (f FilterFunc) Filter(object *RNode) (*RNode, error) {
|
||||
return f(object)
|
||||
}
|
||||
|
||||
// TypeMeta partially copies apimachinery/pkg/apis/meta/v1.TypeMeta
|
||||
// No need for a direct dependence; the fields are stable.
|
||||
type TypeMeta struct {
|
||||
// APIVersion is the apiVersion field of a Resource
|
||||
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
|
||||
// Kind is the kind field of a Resource
|
||||
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
|
||||
}
|
||||
|
||||
// NameMeta contains name information.
|
||||
type NameMeta struct {
|
||||
// Name is the metadata.name field of a Resource
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
// Namespace is the metadata.namespace field of a Resource
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
// ResourceMeta contains the metadata for a both Resource Type and Resource.
|
||||
type ResourceMeta struct {
|
||||
TypeMeta `json:",inline" yaml:",inline"`
|
||||
// ObjectMeta is the metadata field of a Resource
|
||||
ObjectMeta `yaml:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
// ObjectMeta contains metadata about a Resource
|
||||
type ObjectMeta struct {
|
||||
NameMeta `json:",inline" yaml:",inline"`
|
||||
// Labels is the metadata.labels field of a Resource
|
||||
Labels map[string]string `yaml:"labels,omitempty"`
|
||||
// Annotations is the metadata.annotations field of a Resource.
|
||||
Annotations map[string]string `yaml:"annotations,omitempty"`
|
||||
}
|
||||
|
||||
// GetIdentifier returns a ResourceIdentifier that includes
|
||||
// the information needed to uniquely identify a resource in a cluster.
|
||||
func (m *ResourceMeta) GetIdentifier() ResourceIdentifier {
|
||||
return ResourceIdentifier{
|
||||
TypeMeta: m.TypeMeta,
|
||||
NameMeta: m.NameMeta,
|
||||
}
|
||||
}
|
||||
|
||||
// ResourceIdentifier contains the information needed to uniquely
|
||||
// identify a resource in a cluster.
|
||||
type ResourceIdentifier struct {
|
||||
TypeMeta `json:",inline" yaml:",inline"`
|
||||
NameMeta `json:",inline" yaml:",inline"`
|
||||
}
|
||||
|
||||
// Comments struct is comment yaml comment types
|
||||
type Comments struct {
|
||||
LineComment string `yaml:"lineComment,omitempty"`
|
||||
HeadComment string `yaml:"headComment,omitempty"`
|
||||
FootComment string `yaml:"footComment,omitempty"`
|
||||
}
|
||||
|
||||
func (r *ResourceIdentifier) GetName() string {
|
||||
return r.Name
|
||||
}
|
||||
|
||||
func (r *ResourceIdentifier) GetNamespace() string {
|
||||
return r.Namespace
|
||||
}
|
||||
|
||||
func (r *ResourceIdentifier) GetAPIVersion() string {
|
||||
return r.APIVersion
|
||||
}
|
||||
|
||||
func (r *ResourceIdentifier) GetKind() string {
|
||||
return r.Kind
|
||||
}
|
||||
|
||||
const (
|
||||
Trim = "Trim"
|
||||
Flow = "Flow"
|
||||
)
|
||||
|
||||
// String returns a string value for a Node, applying the supplied formatting options
|
||||
func String(node *yaml.Node, opts ...string) (string, error) {
|
||||
if node == nil {
|
||||
return "", nil
|
||||
}
|
||||
optsSet := sets.String{}
|
||||
optsSet.Insert(opts...)
|
||||
if optsSet.Has(Flow) {
|
||||
oldStyle := node.Style
|
||||
defer func() {
|
||||
node.Style = oldStyle
|
||||
}()
|
||||
node.Style = yaml.FlowStyle
|
||||
}
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
e := NewEncoder(b)
|
||||
err := e.Encode(node)
|
||||
e.Close()
|
||||
val := b.String()
|
||||
if optsSet.Has(Trim) {
|
||||
val = strings.TrimSpace(val)
|
||||
}
|
||||
return val, errors.Wrap(err)
|
||||
}
|
||||
|
||||
// MergeOptionsListIncreaseDirection is the type of list growth in merge
|
||||
type MergeOptionsListIncreaseDirection int
|
||||
|
||||
const (
|
||||
MergeOptionsListAppend MergeOptionsListIncreaseDirection = iota
|
||||
MergeOptionsListPrepend
|
||||
)
|
||||
|
||||
// MergeOptions is a struct which contains the options for merge
|
||||
type MergeOptions struct {
|
||||
// ListIncreaseDirection indicates should merge function prepend the items from
|
||||
// source list to destination or append.
|
||||
ListIncreaseDirection MergeOptionsListIncreaseDirection
|
||||
}
|
||||
Reference in New Issue
Block a user