mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 19:31:44 +00:00
Merge pull request #64449 from deads2k/cli-72-scrub
Automatic merge from submit-queue (batch tested with PRs 63328, 64316, 64444, 64449, 64453). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. cleanup some dead kubectl code and narrow scope of helpers Found a lot of dead code in kubectl factory that we should scrub out /assign @soltysh /assign @juanvallejo ```release-note NONE ```
This commit is contained in:
commit
1123e5dd82
@ -148,7 +148,6 @@ pkg/kubectl/cmd/templates
|
||||
pkg/kubectl/cmd/testing
|
||||
pkg/kubectl/cmd/util
|
||||
pkg/kubectl/cmd/util/editor
|
||||
pkg/kubectl/cmd/util/jsonmerge
|
||||
pkg/kubectl/cmd/util/sanity
|
||||
pkg/kubectl/cmd/wait
|
||||
pkg/kubectl/genericclioptions
|
||||
@ -156,7 +155,6 @@ pkg/kubectl/genericclioptions/printers
|
||||
pkg/kubectl/genericclioptions/resource
|
||||
pkg/kubectl/metricsutil
|
||||
pkg/kubectl/util
|
||||
pkg/kubectl/util/crlf
|
||||
pkg/kubectl/util/slice
|
||||
pkg/kubelet
|
||||
pkg/kubelet/apis
|
||||
|
@ -40,7 +40,6 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/dynamic"
|
||||
scaleclient "k8s.io/client-go/scale"
|
||||
oapi "k8s.io/kube-openapi/pkg/util/proto"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
@ -79,7 +78,6 @@ type ApplyOptions struct {
|
||||
Validator validation.Schema
|
||||
Builder *resource.Builder
|
||||
Mapper meta.RESTMapper
|
||||
Scaler scaleclient.ScalesGetter
|
||||
DynamicClient dynamic.Interface
|
||||
OpenAPISchema openapi.Resources
|
||||
|
||||
@ -220,11 +218,6 @@ func (o *ApplyOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
return err
|
||||
}
|
||||
|
||||
o.Scaler, err = cmdutil.ScaleClientFn(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.DynamicClient, err = f.DynamicClient()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -493,7 +486,6 @@ func (o *ApplyOptions) Run() error {
|
||||
cascade: o.DeleteOptions.Cascade,
|
||||
dryRun: o.DryRun,
|
||||
gracePeriod: o.DeleteOptions.GracePeriod,
|
||||
scaler: o.Scaler,
|
||||
|
||||
toPrinter: o.ToPrinter,
|
||||
|
||||
@ -583,8 +575,6 @@ type pruner struct {
|
||||
dryRun bool
|
||||
gracePeriod int
|
||||
|
||||
scaler scaleclient.ScalesGetter
|
||||
|
||||
toPrinter func(string) (printers.ResourcePrinter, error)
|
||||
|
||||
out io.Writer
|
||||
|
@ -21,9 +21,9 @@ go_library(
|
||||
deps = [
|
||||
"//pkg/apis/rbac:go_default_library",
|
||||
"//pkg/kubectl:go_default_library",
|
||||
"//pkg/kubectl/cmd/set/env:go_default_library",
|
||||
"//pkg/kubectl/cmd/templates:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubectl/cmd/util/env:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions/printers:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions/resource:go_default_library",
|
||||
@ -96,7 +96,10 @@ filegroup(
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/kubectl/cmd/set/env:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = [
|
||||
"//build/visible_to:pkg_kubectl_cmd_set_CONSUMERS",
|
||||
|
@ -7,7 +7,7 @@ go_library(
|
||||
"env_parse.go",
|
||||
"env_resolve.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/util/env",
|
||||
importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/set/env",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/api/v1/resource:go_default_library",
|
@ -14,5 +14,5 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package env provides functions to incorporate environment variables into kubectl commands.
|
||||
package env // import "k8s.io/kubernetes/pkg/kubectl/cmd/util/env"
|
||||
// Package env provides functions to incorporate environment variables into set env.
|
||||
package env
|
@ -20,7 +20,6 @@ import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
@ -28,24 +27,6 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
// Env returns an environment variable if not nil, or a default value.
|
||||
func Env(key string, defaultValue string) string {
|
||||
val := os.Getenv(key)
|
||||
if len(val) == 0 {
|
||||
return defaultValue
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// GetEnv returns an environment value if not nil, and an ok boolean.
|
||||
func GetEnv(key string) (string, bool) {
|
||||
val := os.Getenv(key)
|
||||
if len(val) == 0 {
|
||||
return "", false
|
||||
}
|
||||
return val, true
|
||||
}
|
||||
|
||||
var argumentEnvironment = regexp.MustCompile("(?ms)^(.+)\\=(.*)$")
|
||||
var validArgumentEnvironment = regexp.MustCompile("(?ms)^(\\w+)\\=(.*)$")
|
||||
|
@ -19,36 +19,9 @@ package env
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ExampleEnv_defaultValue() {
|
||||
fmt.Println(Env("TESTENVVAR", "default"))
|
||||
// Output: default
|
||||
}
|
||||
|
||||
func ExampleEnv_variableExists() {
|
||||
os.Setenv("TESTENVVAR", "test value")
|
||||
defer os.Unsetenv("TESTENVVAR")
|
||||
fmt.Println(Env("TESTENVVAR", "default"))
|
||||
// Output: test value
|
||||
}
|
||||
|
||||
func ExampleGetEnv_variableExists() {
|
||||
os.Setenv("THISVAREXISTS", "value")
|
||||
defer os.Unsetenv("THISVAREXISTS")
|
||||
fmt.Println(GetEnv("THISVAREXISTS"))
|
||||
// Output:
|
||||
// value true
|
||||
}
|
||||
|
||||
func ExampleGetEnv_variableDoesNotExist() {
|
||||
fmt.Println(GetEnv("THISVARDOESNOTEXIST"))
|
||||
// Output:
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleIsEnvironmentArgument_true() {
|
||||
test := "returns=true"
|
||||
fmt.Println(IsEnvironmentArgument(test))
|
@ -31,9 +31,9 @@ import (
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
envutil "k8s.io/kubernetes/pkg/kubectl/cmd/set/env"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
envutil "k8s.io/kubernetes/pkg/kubectl/cmd/util/env"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/printers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
|
@ -58,10 +58,7 @@ go_library(
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"factory_test.go",
|
||||
"helpers_test.go",
|
||||
],
|
||||
srcs = ["helpers_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/api/testapi:go_default_library",
|
||||
@ -90,8 +87,6 @@ filegroup(
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/kubectl/cmd/util/editor:all-srcs",
|
||||
"//pkg/kubectl/cmd/util/env:all-srcs",
|
||||
"//pkg/kubectl/cmd/util/jsonmerge:all-srcs",
|
||||
"//pkg/kubectl/cmd/util/openapi:all-srcs",
|
||||
"//pkg/kubectl/cmd/util/sanity:all-srcs",
|
||||
],
|
||||
|
@ -18,11 +18,11 @@ go_library(
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/kubectl:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubectl/cmd/util/editor/crlf:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions/printers:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions/resource:go_default_library",
|
||||
"//pkg/kubectl/scheme:go_default_library",
|
||||
"//pkg/kubectl/util/crlf:go_default_library",
|
||||
"//pkg/kubectl/util/term:go_default_library",
|
||||
"//vendor/github.com/evanphx/json-patch:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
@ -57,7 +57,10 @@ filegroup(
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/kubectl/cmd/util/editor/crlf:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = [
|
||||
"//build/visible_to:pkg_kubectl_cmd_util_editor_CONSUMERS",
|
||||
|
@ -8,7 +8,7 @@ load(
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["crlf.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/kubectl/util/crlf",
|
||||
importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/util/editor/crlf",
|
||||
)
|
||||
|
||||
filegroup(
|
@ -51,7 +51,7 @@ func (w crlfWriter) Write(b []byte) (n int, err error) {
|
||||
}
|
||||
return written + n, err
|
||||
}
|
||||
written += 1
|
||||
written++
|
||||
i = next + 1
|
||||
}
|
||||
}
|
@ -45,11 +45,11 @@ import (
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util/editor/crlf"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/printers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/crlf"
|
||||
)
|
||||
|
||||
// EditOptions contains all the options for running edit cli command.
|
||||
|
@ -17,15 +17,10 @@ limitations under the License.
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
@ -73,26 +68,3 @@ type Factory interface {
|
||||
// OpenAPISchema returns the schema openapi schema definition
|
||||
OpenAPISchema() (openapi.Resources, error)
|
||||
}
|
||||
|
||||
func makePortsString(ports []api.ServicePort, useNodePort bool) string {
|
||||
pieces := make([]string, len(ports))
|
||||
for ix := range ports {
|
||||
var port int32
|
||||
if useNodePort {
|
||||
port = ports[ix].NodePort
|
||||
} else {
|
||||
port = ports[ix].Port
|
||||
}
|
||||
pieces[ix] = fmt.Sprintf("%s:%d", strings.ToLower(string(ports[ix].Protocol)), port)
|
||||
}
|
||||
return strings.Join(pieces, ",")
|
||||
}
|
||||
|
||||
// Extracts the protocols exposed by a service from the given service spec.
|
||||
func getServiceProtocols(spec api.ServiceSpec) map[string]string {
|
||||
result := make(map[string]string)
|
||||
for _, servicePort := range spec.Ports {
|
||||
result[strconv.Itoa(int(servicePort.Port))] = string(servicePort.Protocol)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
@ -28,7 +28,6 @@ import (
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
scaleclient "k8s.io/client-go/scale"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
@ -189,24 +188,6 @@ func (f *factoryImpl) OpenAPISchema() (openapi.Resources, error) {
|
||||
return f.openAPIGetter.getter.Get()
|
||||
}
|
||||
|
||||
func (f *factoryImpl) ScaleClient() (scaleclient.ScalesGetter, error) {
|
||||
discoClient, err := f.clientGetter.ToDiscoveryClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
restClient, err := f.RESTClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resolver := scaleclient.NewDiscoveryScaleKindResolver(discoClient)
|
||||
mapper, err := f.clientGetter.ToRESTMapper()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return scaleclient.New(restClient, mapper, dynamic.LegacyAPIPathResolverFunc, resolver), nil
|
||||
}
|
||||
|
||||
// this method exists to help us find the points still relying on internal types.
|
||||
func InternalVersionDecoder() runtime.Decoder {
|
||||
return legacyscheme.Codecs.UniversalDecoder()
|
||||
|
@ -1,79 +0,0 @@
|
||||
/*
|
||||
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 util
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
)
|
||||
|
||||
func TestMakePortsString(t *testing.T) {
|
||||
tests := []struct {
|
||||
ports []api.ServicePort
|
||||
useNodePort bool
|
||||
expectedOutput string
|
||||
}{
|
||||
{ports: nil, expectedOutput: ""},
|
||||
{ports: []api.ServicePort{}, expectedOutput: ""},
|
||||
{ports: []api.ServicePort{
|
||||
{
|
||||
Port: 80,
|
||||
Protocol: "TCP",
|
||||
},
|
||||
},
|
||||
expectedOutput: "tcp:80",
|
||||
},
|
||||
{ports: []api.ServicePort{
|
||||
{
|
||||
Port: 80,
|
||||
Protocol: "TCP",
|
||||
},
|
||||
{
|
||||
Port: 8080,
|
||||
Protocol: "UDP",
|
||||
},
|
||||
{
|
||||
Port: 9000,
|
||||
Protocol: "TCP",
|
||||
},
|
||||
},
|
||||
expectedOutput: "tcp:80,udp:8080,tcp:9000",
|
||||
},
|
||||
{ports: []api.ServicePort{
|
||||
{
|
||||
Port: 80,
|
||||
NodePort: 9090,
|
||||
Protocol: "TCP",
|
||||
},
|
||||
{
|
||||
Port: 8080,
|
||||
NodePort: 80,
|
||||
Protocol: "UDP",
|
||||
},
|
||||
},
|
||||
useNodePort: true,
|
||||
expectedOutput: "tcp:9090,udp:80",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
output := makePortsString(test.ports, test.useNodePort)
|
||||
if output != test.expectedOutput {
|
||||
t.Errorf("expected: %s, saw: %s.", test.expectedOutput, output)
|
||||
}
|
||||
}
|
||||
}
|
@ -62,7 +62,6 @@ const (
|
||||
ConfigMapV1GeneratorName = "configmap/v1"
|
||||
ClusterRoleBindingV1GeneratorName = "clusterrolebinding.rbac.authorization.k8s.io/v1alpha1"
|
||||
RoleBindingV1GeneratorName = "rolebinding.rbac.authorization.k8s.io/v1alpha1"
|
||||
ClusterV1Beta1GeneratorName = "cluster/v1beta1"
|
||||
PodDisruptionBudgetV1GeneratorName = "poddisruptionbudget/v1beta1"
|
||||
PodDisruptionBudgetV2GeneratorName = "poddisruptionbudget/v1beta1/v2"
|
||||
PriorityClassV1Alpha1GeneratorName = "priorityclass/v1alpha1"
|
||||
|
@ -300,16 +300,6 @@ func IsFilenameSliceEmpty(filenames []string) bool {
|
||||
return len(filenames) == 0
|
||||
}
|
||||
|
||||
// Whether this cmd need watching objects.
|
||||
func isWatch(cmd *cobra.Command) bool {
|
||||
if w, err := cmd.Flags().GetBool("watch"); err == nil && w {
|
||||
return true
|
||||
}
|
||||
|
||||
wo, err := cmd.Flags().GetBool("watch-only")
|
||||
return err == nil && wo
|
||||
}
|
||||
|
||||
func GetFlagString(cmd *cobra.Command, flag string) string {
|
||||
s, err := cmd.Flags().GetString(flag)
|
||||
if err != nil {
|
||||
@ -336,15 +326,6 @@ func GetFlagStringArray(cmd *cobra.Command, flag string) []string {
|
||||
return s
|
||||
}
|
||||
|
||||
// GetWideFlag is used to determine if "-o wide" is used
|
||||
func GetWideFlag(cmd *cobra.Command) bool {
|
||||
f := cmd.Flags().Lookup("output")
|
||||
if f != nil && f.Value != nil && f.Value.String() == "wide" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func GetFlagBool(cmd *cobra.Command, flag string) bool {
|
||||
b, err := cmd.Flags().GetBool(flag)
|
||||
if err != nil {
|
||||
|
@ -1,32 +0,0 @@
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["jsonmerge.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/util/jsonmerge",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/evanphx/json-patch:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/mergepatch:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/yaml:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = [
|
||||
"//build/visible_to:pkg_kubectl_cmd_util_jsonmerge_CONSUMERS",
|
||||
],
|
||||
)
|
@ -1,193 +0,0 @@
|
||||
/*
|
||||
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 jsonmerge
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/evanphx/json-patch"
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/mergepatch"
|
||||
"k8s.io/apimachinery/pkg/util/yaml"
|
||||
)
|
||||
|
||||
// Delta represents a change between two JSON documents.
|
||||
type Delta struct {
|
||||
original []byte
|
||||
edit []byte
|
||||
|
||||
preconditions []PreconditionFunc
|
||||
}
|
||||
|
||||
// PreconditionFunc is a test to verify that an incompatible change
|
||||
// has occurred before an Apply can be successful.
|
||||
type PreconditionFunc func(interface{}) (hold bool, message string)
|
||||
|
||||
// AddPreconditions adds precondition checks to a change which must
|
||||
// be satisfied before an Apply is considered successful. If a
|
||||
// precondition returns false, the Apply is failed with
|
||||
// ErrPreconditionFailed.
|
||||
func (d *Delta) AddPreconditions(fns ...PreconditionFunc) {
|
||||
d.preconditions = append(d.preconditions, fns...)
|
||||
}
|
||||
|
||||
// RequireKeyUnchanged creates a precondition function that fails
|
||||
// if the provided key is present in the diff (indicating its value
|
||||
// has changed).
|
||||
func RequireKeyUnchanged(key string) PreconditionFunc {
|
||||
return func(diff interface{}) (bool, string) {
|
||||
m, ok := diff.(map[string]interface{})
|
||||
if !ok {
|
||||
return true, ""
|
||||
}
|
||||
// the presence of key in a diff means that its value has been changed, therefore
|
||||
// we should fail the precondition.
|
||||
_, ok = m[key]
|
||||
if ok {
|
||||
return false, key + " should not be changed\n"
|
||||
} else {
|
||||
return true, ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RequireMetadataKeyUnchanged creates a precondition function that fails
|
||||
// if the metadata.key is present in the diff (indicating its value
|
||||
// has changed).
|
||||
func RequireMetadataKeyUnchanged(key string) PreconditionFunc {
|
||||
return func(diff interface{}) (bool, string) {
|
||||
m, ok := diff.(map[string]interface{})
|
||||
if !ok {
|
||||
return true, ""
|
||||
}
|
||||
m1, ok := m["metadata"]
|
||||
if !ok {
|
||||
return true, ""
|
||||
}
|
||||
m2, ok := m1.(map[string]interface{})
|
||||
if !ok {
|
||||
return true, ""
|
||||
}
|
||||
_, ok = m2[key]
|
||||
if ok {
|
||||
return false, "metadata." + key + " should not be changed\n"
|
||||
} else {
|
||||
return true, ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestPreconditions test if preconditions hold given the edit
|
||||
func TestPreconditionsHold(edit []byte, preconditions []PreconditionFunc) (bool, string) {
|
||||
diff := make(map[string]interface{})
|
||||
if err := json.Unmarshal(edit, &diff); err != nil {
|
||||
return false, err.Error()
|
||||
}
|
||||
for _, fn := range preconditions {
|
||||
if hold, msg := fn(diff); !hold {
|
||||
return false, msg
|
||||
}
|
||||
}
|
||||
return true, ""
|
||||
}
|
||||
|
||||
// NewDelta accepts two JSON or YAML documents and calculates the difference
|
||||
// between them. It returns a Delta object which can be used to resolve
|
||||
// conflicts against a third version with a common parent, or an error
|
||||
// if either document is in error.
|
||||
func NewDelta(from, to []byte) (*Delta, error) {
|
||||
d := &Delta{}
|
||||
before, err := yaml.ToJSON(from)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
after, err := yaml.ToJSON(to)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
diff, err := jsonpatch.CreateMergePatch(before, after)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
glog.V(6).Infof("Patch created from:\n%s\n%s\n%s", string(before), string(after), string(diff))
|
||||
d.original = before
|
||||
d.edit = diff
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// Apply attempts to apply the changes described by Delta onto latest,
|
||||
// returning an error if the changes cannot be applied cleanly.
|
||||
// IsConflicting will be true if the changes overlap, otherwise a
|
||||
// generic error will be returned.
|
||||
func (d *Delta) Apply(latest []byte) ([]byte, error) {
|
||||
base, err := yaml.ToJSON(latest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
changes, err := jsonpatch.CreateMergePatch(d.original, base)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
diff1 := make(map[string]interface{})
|
||||
if err := json.Unmarshal(d.edit, &diff1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
diff2 := make(map[string]interface{})
|
||||
if err := json.Unmarshal(changes, &diff2); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, fn := range d.preconditions {
|
||||
hold1, _ := fn(diff1)
|
||||
hold2, _ := fn(diff2)
|
||||
if !hold1 || !hold2 {
|
||||
return nil, ErrPreconditionFailed
|
||||
}
|
||||
}
|
||||
|
||||
glog.V(6).Infof("Testing for conflict between:\n%s\n%s", string(d.edit), string(changes))
|
||||
hasConflicts, err := mergepatch.HasConflicts(diff1, diff2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if hasConflicts {
|
||||
return nil, ErrConflict
|
||||
}
|
||||
|
||||
return jsonpatch.MergePatch(base, d.edit)
|
||||
}
|
||||
|
||||
// IsConflicting returns true if the provided error indicates a
|
||||
// conflict exists between the original changes and the applied
|
||||
// changes.
|
||||
func IsConflicting(err error) bool {
|
||||
return err == ErrConflict
|
||||
}
|
||||
|
||||
// IsPreconditionFailed returns true if the provided error indicates
|
||||
// a Delta precondition did not succeed.
|
||||
func IsPreconditionFailed(err error) bool {
|
||||
return err == ErrPreconditionFailed
|
||||
}
|
||||
|
||||
var ErrPreconditionFailed = fmt.Errorf("a precondition failed")
|
||||
var ErrConflict = fmt.Errorf("changes are in conflict")
|
||||
|
||||
func (d *Delta) Edit() []byte {
|
||||
return d.edit
|
||||
}
|
@ -98,7 +98,6 @@ filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/kubectl/util/crlf:all-srcs",
|
||||
"//pkg/kubectl/util/hash:all-srcs",
|
||||
"//pkg/kubectl/util/i18n:all-srcs",
|
||||
"//pkg/kubectl/util/logs:all-srcs",
|
||||
|
Loading…
Reference in New Issue
Block a user