From c78857220a0464967f07d4b9d91281aed444d56f Mon Sep 17 00:00:00 2001 From: Angus Lees <gus@inodes.org> Date: Mon, 17 Jul 2017 14:57:17 +1000 Subject: [PATCH] Set appropriate delete option for server version Annoyingly, delete options `OrphanDependents` and `PropagationPolicy` are mutually exclusive. This change compares the k8s server version to see if the server is going to look for the newer PropagationPolicy. Fixes a78be141de964cfde0fd9197867962202f1f4389 (aka PR #59) --- cmd/delete.go | 17 ++++++++---- utils/meta.go | 62 +++++++++++++++++++++++++++++++++++++++++++ utils/meta_test.go | 65 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 utils/meta.go create mode 100644 utils/meta_test.go diff --git a/cmd/delete.go b/cmd/delete.go index 9da63f41..5826c21c 100644 --- a/cmd/delete.go +++ b/cmd/delete.go @@ -41,8 +41,6 @@ var deleteCmd = &cobra.Command{ Short: "Delete Kubernetes resources described in local config", RunE: func(cmd *cobra.Command, args []string) error { flags := cmd.Flags() - boolFalse := false - deletePolicyForeground := metav1.DeletePropagationForeground gracePeriod, err := flags.GetInt64(flagGracePeriod) if err != nil { @@ -64,13 +62,22 @@ var deleteCmd = &cobra.Command{ return err } + version, err := utils.FetchVersion(disco) + if err != nil { + return err + } + sort.Sort(sort.Reverse(utils.DependencyOrder(objs))) - deleteOpts := metav1.DeleteOptions{ + deleteOpts := metav1.DeleteOptions{} + if version.Compare(1, 6) < 0 { // 1.5.x option - OrphanDependents: &boolFalse, + boolFalse := false + deleteOpts.OrphanDependents = &boolFalse + } else { // 1.6.x option (NB: Background is broken) - PropagationPolicy: &deletePolicyForeground, + fg := metav1.DeletePropagationForeground + deleteOpts.PropagationPolicy = &fg } if gracePeriod >= 0 { deleteOpts.GracePeriodSeconds = &gracePeriod diff --git a/utils/meta.go b/utils/meta.go new file mode 100644 index 00000000..9d448a44 --- /dev/null +++ b/utils/meta.go @@ -0,0 +1,62 @@ +package utils + +import ( + "fmt" + "strconv" + + "k8s.io/apimachinery/pkg/version" + "k8s.io/client-go/discovery" +) + +// ServerVersion captures k8s major.minor version in a parsed form +type ServerVersion struct { + Major int + Minor int +} + +// ParseVersion parses version.Info into a ServerVersion struct +func ParseVersion(v *version.Info) (ret ServerVersion, err error) { + ret.Major, err = strconv.Atoi(v.Major) + if err != nil { + return + } + ret.Minor, err = strconv.Atoi(v.Minor) + if err != nil { + return + } + return +} + +// FetchVersion fetches version information from discovery client, and parses +func FetchVersion(v discovery.ServerVersionInterface) (ret ServerVersion, err error) { + version, err := v.ServerVersion() + if err != nil { + return ServerVersion{}, err + } + return ParseVersion(version) +} + +// Compare returns -1/0/+1 iff v is less than / equal / greater than major.minor +func (v ServerVersion) Compare(major, minor int) int { + a := v.Major + b := major + + if a == b { + a = v.Minor + b = minor + } + + var res int + if a > b { + res = 1 + } else if a == b { + res = 0 + } else { + res = -1 + } + return res +} + +func (v ServerVersion) String() string { + return fmt.Sprintf("%d.%d", v.Major, v.Minor) +} diff --git a/utils/meta_test.go b/utils/meta_test.go new file mode 100644 index 00000000..2bcf32e9 --- /dev/null +++ b/utils/meta_test.go @@ -0,0 +1,65 @@ +package utils + +import ( + "testing" + + "k8s.io/apimachinery/pkg/version" +) + +func TestParseVersion(t *testing.T) { + tests := []struct { + input version.Info + expected ServerVersion + error bool + }{ + { + input: version.Info{Major: "1", Minor: "6"}, + expected: ServerVersion{Major: 1, Minor: 6}, + }, + { + input: version.Info{Major: "1", Minor: "70"}, + expected: ServerVersion{Major: 1, Minor: 70}, + }, + { + input: version.Info{Major: "1", Minor: "6x"}, + error: true, + }, + } + + for _, test := range tests { + v, err := ParseVersion(&test.input) + if test.error { + if err == nil { + t.Errorf("test %s should have failed and did not", test.input) + } + continue + } + if err != nil { + t.Errorf("test %v failed: %v", test.input, err) + continue + } + if v != test.expected { + t.Errorf("Expected %v, got %v", test.expected, v) + } + } +} + +func TestVersionCompare(t *testing.T) { + v := ServerVersion{Major: 2, Minor: 3} + tests := []struct { + major, minor, result int + }{ + {major: 1, minor: 0, result: 1}, + {major: 2, minor: 0, result: 1}, + {major: 2, minor: 2, result: 1}, + {major: 2, minor: 3, result: 0}, + {major: 2, minor: 4, result: -1}, + {major: 3, minor: 0, result: -1}, + } + for _, test := range tests { + res := v.Compare(test.major, test.minor) + if res != test.result { + t.Errorf("%d.%d => Expected %d, got %d", test.major, test.minor, test.result, res) + } + } +} -- GitLab