diff --git a/pkg/instancegroups/BUILD.bazel b/pkg/instancegroups/BUILD.bazel index 1422238916..d14c8991ca 100644 --- a/pkg/instancegroups/BUILD.bazel +++ b/pkg/instancegroups/BUILD.bazel @@ -14,7 +14,6 @@ go_library( "//pkg/apis/kops:go_default_library", "//pkg/client/simple:go_default_library", "//pkg/cloudinstances:go_default_library", - "//pkg/drain:go_default_library", "//pkg/featureflag:go_default_library", "//pkg/validation:go_default_library", "//upup/pkg/fi:go_default_library", @@ -27,6 +26,7 @@ go_library( "//vendor/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library", "//vendor/k8s.io/client-go/kubernetes:go_default_library", "//vendor/k8s.io/klog:go_default_library", + "//vendor/k8s.io/kubectl/pkg/drain:go_default_library", ], ) diff --git a/vendor/github.com/bazelbuild/bazel-gazelle/cmd/gazelle/BUILD.bazel b/vendor/github.com/bazelbuild/bazel-gazelle/cmd/gazelle/BUILD.bazel index 99b33f58c2..0cac80b7f0 100644 --- a/vendor/github.com/bazelbuild/bazel-gazelle/cmd/gazelle/BUILD.bazel +++ b/vendor/github.com/bazelbuild/bazel-gazelle/cmd/gazelle/BUILD.bazel @@ -1,35 +1,13 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") -load("@bazel_gazelle//:def.bzl", "DEFAULT_LANGUAGES", "gazelle_binary") - -gazelle_binary( - name = "gazelle", - languages = DEFAULT_LANGUAGES, - msan = "off", - pure = "off", - race = "off", - static = "off", - visibility = ["//visibility:public"], -) - -gazelle_binary( - name = "gazelle_pure", - languages = DEFAULT_LANGUAGES, - msan = "off", - pure = "on", - race = "off", - static = "off", - tags = ["manual"], - visibility = ["//visibility:public"], -) +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") go_library( name = "go_default_library", - # keep srcs = [ "diff.go", "fix.go", "fix-update.go", "gazelle.go", + "langs.go", "metaresolver.go", "print.go", "update-repos.go", @@ -37,8 +15,7 @@ go_library( ], importmap = "k8s.io/kops/vendor/github.com/bazelbuild/bazel-gazelle/cmd/gazelle", importpath = "github.com/bazelbuild/bazel-gazelle/cmd/gazelle", - tags = ["manual"], - visibility = ["//visibility:public"], + visibility = ["//visibility:private"], deps = [ "//vendor/github.com/bazelbuild/bazel-gazelle/config:go_default_library", "//vendor/github.com/bazelbuild/bazel-gazelle/flag:go_default_library", @@ -56,33 +33,8 @@ go_library( ], ) -go_test( - name = "go_default_test", - size = "small", - srcs = [ - "langs.go", # keep - ], - args = ["-go_sdk=go_sdk"], - data = ["@go_sdk//:files"], -) - -filegroup( - name = "all_files", - testonly = True, - srcs = [ - "BUILD.bazel", - "diff.go", - "diff_test.go", - "fix.go", - "fix-update.go", - "fix_test.go", - "gazelle.go", - "integration_test.go", - "langs.go", - "metaresolver.go", - "print.go", - "update-repos.go", - "version.go", - ], +go_binary( + name = "gazelle", + embed = [":go_default_library"], visibility = ["//visibility:public"], ) diff --git a/vendor/github.com/bazelbuild/bazel-gazelle/config/BUILD.bazel b/vendor/github.com/bazelbuild/bazel-gazelle/config/BUILD.bazel index 2340a49f28..1824d560e7 100644 --- a/vendor/github.com/bazelbuild/bazel-gazelle/config/BUILD.bazel +++ b/vendor/github.com/bazelbuild/bazel-gazelle/config/BUILD.bazel @@ -14,15 +14,3 @@ go_library( "//vendor/github.com/bazelbuild/bazel-gazelle/rule:go_default_library", ], ) - -filegroup( - name = "all_files", - testonly = True, - srcs = [ - "BUILD.bazel", - "config.go", - "config_test.go", - "constants.go", - ], - visibility = ["//visibility:public"], -) diff --git a/vendor/github.com/bazelbuild/bazel-gazelle/flag/BUILD.bazel b/vendor/github.com/bazelbuild/bazel-gazelle/flag/BUILD.bazel index c361004cac..3e31143b9a 100644 --- a/vendor/github.com/bazelbuild/bazel-gazelle/flag/BUILD.bazel +++ b/vendor/github.com/bazelbuild/bazel-gazelle/flag/BUILD.bazel @@ -7,13 +7,3 @@ go_library( importpath = "github.com/bazelbuild/bazel-gazelle/flag", visibility = ["//visibility:public"], ) - -filegroup( - name = "all_files", - testonly = True, - srcs = [ - "BUILD.bazel", - "flag.go", - ], - visibility = ["//visibility:public"], -) diff --git a/vendor/github.com/bazelbuild/bazel-gazelle/internal/version/BUILD.bazel b/vendor/github.com/bazelbuild/bazel-gazelle/internal/version/BUILD.bazel index 7295c679c3..c11ea76d73 100644 --- a/vendor/github.com/bazelbuild/bazel-gazelle/internal/version/BUILD.bazel +++ b/vendor/github.com/bazelbuild/bazel-gazelle/internal/version/BUILD.bazel @@ -5,16 +5,5 @@ go_library( srcs = ["version.go"], importmap = "k8s.io/kops/vendor/github.com/bazelbuild/bazel-gazelle/internal/version", importpath = "github.com/bazelbuild/bazel-gazelle/internal/version", - visibility = ["//:__subpackages__"], -) - -filegroup( - name = "all_files", - testonly = True, - srcs = [ - "BUILD.bazel", - "version.go", - "version_test.go", - ], - visibility = ["//visibility:public"], + visibility = ["//vendor/github.com/bazelbuild/bazel-gazelle:__subpackages__"], ) diff --git a/vendor/github.com/bazelbuild/bazel-gazelle/internal/wspace/BUILD.bazel b/vendor/github.com/bazelbuild/bazel-gazelle/internal/wspace/BUILD.bazel index c9d4fc0a66..44a46e6311 100644 --- a/vendor/github.com/bazelbuild/bazel-gazelle/internal/wspace/BUILD.bazel +++ b/vendor/github.com/bazelbuild/bazel-gazelle/internal/wspace/BUILD.bazel @@ -5,16 +5,5 @@ go_library( srcs = ["finder.go"], importmap = "k8s.io/kops/vendor/github.com/bazelbuild/bazel-gazelle/internal/wspace", importpath = "github.com/bazelbuild/bazel-gazelle/internal/wspace", - visibility = ["//visibility:public"], -) - -filegroup( - name = "all_files", - testonly = True, - srcs = [ - "BUILD.bazel", - "finder.go", - "finder_test.go", - ], - visibility = ["//visibility:public"], + visibility = ["//vendor/github.com/bazelbuild/bazel-gazelle:__subpackages__"], ) diff --git a/vendor/github.com/bazelbuild/bazel-gazelle/label/BUILD.bazel b/vendor/github.com/bazelbuild/bazel-gazelle/label/BUILD.bazel index 83c7899adb..20cfb261ce 100644 --- a/vendor/github.com/bazelbuild/bazel-gazelle/label/BUILD.bazel +++ b/vendor/github.com/bazelbuild/bazel-gazelle/label/BUILD.bazel @@ -8,14 +8,3 @@ go_library( visibility = ["//visibility:public"], deps = ["//vendor/github.com/bazelbuild/bazel-gazelle/pathtools:go_default_library"], ) - -filegroup( - name = "all_files", - testonly = True, - srcs = [ - "BUILD.bazel", - "label.go", - "label_test.go", - ], - visibility = ["//visibility:public"], -) diff --git a/vendor/github.com/bazelbuild/bazel-gazelle/language/BUILD.bazel b/vendor/github.com/bazelbuild/bazel-gazelle/language/BUILD.bazel index b9183426d9..59ef2756c5 100644 --- a/vendor/github.com/bazelbuild/bazel-gazelle/language/BUILD.bazel +++ b/vendor/github.com/bazelbuild/bazel-gazelle/language/BUILD.bazel @@ -16,16 +16,3 @@ go_library( "//vendor/github.com/bazelbuild/bazel-gazelle/rule:go_default_library", ], ) - -filegroup( - name = "all_files", - testonly = True, - srcs = [ - "BUILD.bazel", - "lang.go", - "update.go", - "//language/go:all_files", - "//language/proto:all_files", - ], - visibility = ["//visibility:public"], -) diff --git a/vendor/github.com/bazelbuild/bazel-gazelle/language/go/BUILD.bazel b/vendor/github.com/bazelbuild/bazel-gazelle/language/go/BUILD.bazel index b069936959..b35122f7d8 100644 --- a/vendor/github.com/bazelbuild/bazel-gazelle/language/go/BUILD.bazel +++ b/vendor/github.com/bazelbuild/bazel-gazelle/language/go/BUILD.bazel @@ -1,31 +1,4 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") -load(":def.bzl", "std_package_list") - -# gazelle:exclude testdata - -# TODO(jayconrod): test that the checked-in static file matches the generated -# file. The generated code is checked in so that Gazelle can still be built -# with "go get". -std_package_list( - name = "std_package_list", - out = "std_package_list.go", -) - -genrule( - name = "known_proto_imports", - srcs = ["//language/proto:proto.csv"], - outs = ["known_proto_imports.go"], - cmd = "$(location //language/proto/gen:gen_known_imports) -proto_csv $< -known_imports $@ -package golang -var knownProtoImports -key 0 -value 3", - tools = ["//language/proto/gen:gen_known_imports"], -) - -genrule( - name = "known_go_imports", - srcs = ["//language/proto:proto.csv"], - outs = ["known_go_imports.go"], - cmd = "$(location //language/proto/gen:gen_known_imports) -proto_csv $< -known_imports $@ -package golang -var knownGoProtoImports -key 2 -value 3", - tools = ["//language/proto/gen:gen_known_imports"], -) go_library( name = "go_default_library", @@ -65,38 +38,3 @@ go_library( "//vendor/golang.org/x/sync/errgroup:go_default_library", ], ) - -filegroup( - name = "all_files", - testonly = True, - srcs = [ - "BUILD.bazel", - "config.go", - "config_test.go", - "constants.go", - "def.bzl", - "dep.go", - "fileinfo.go", - "fileinfo_go_test.go", - "fileinfo_test.go", - "fix.go", - "fix_test.go", - "generate.go", - "generate_test.go", - "godep.go", - "kinds.go", - "known_go_imports.go", - "known_proto_imports.go", - "lang.go", - "modules.go", - "package.go", - "resolve.go", - "resolve_test.go", - "std_package_list.go", - "stubs_test.go", - "update.go", - "update_import_test.go", - "//language/go/gen_std_package_list:all_files", - ], - visibility = ["//visibility:public"], -) diff --git a/vendor/github.com/bazelbuild/bazel-gazelle/language/proto/BUILD.bazel b/vendor/github.com/bazelbuild/bazel-gazelle/language/proto/BUILD.bazel index c5dd92344f..0b8a46aaa7 100644 --- a/vendor/github.com/bazelbuild/bazel-gazelle/language/proto/BUILD.bazel +++ b/vendor/github.com/bazelbuild/bazel-gazelle/language/proto/BUILD.bazel @@ -1,15 +1,5 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") -# gazelle:exclude testdata - -genrule( - name = "known_imports", - srcs = ["proto.csv"], - outs = ["known_imports.go"], - cmd = "$(location //language/proto/gen:gen_known_imports) -proto_csv $< -known_imports $@ -package proto -var knownImports -key 0 -value 1", - tools = ["//language/proto/gen:gen_known_imports"], -) - go_library( name = "go_default_library", srcs = [ @@ -36,30 +26,3 @@ go_library( "//vendor/github.com/bazelbuild/bazel-gazelle/rule:go_default_library", ], ) - -exports_files(["proto.csv"]) - -filegroup( - name = "all_files", - testonly = True, - srcs = [ - "BUILD.bazel", - "config.go", - "config_test.go", - "constants.go", - "fileinfo.go", - "fileinfo_test.go", - "fix.go", - "generate.go", - "generate_test.go", - "kinds.go", - "known_imports.go", - "lang.go", - "package.go", - "proto.csv", - "resolve.go", - "resolve_test.go", - "//language/proto/gen:all_files", - ], - visibility = ["//visibility:public"], -) diff --git a/vendor/github.com/bazelbuild/bazel-gazelle/merger/BUILD.bazel b/vendor/github.com/bazelbuild/bazel-gazelle/merger/BUILD.bazel index 89fc0c3ce6..ba2108015e 100644 --- a/vendor/github.com/bazelbuild/bazel-gazelle/merger/BUILD.bazel +++ b/vendor/github.com/bazelbuild/bazel-gazelle/merger/BUILD.bazel @@ -11,15 +11,3 @@ go_library( visibility = ["//visibility:public"], deps = ["//vendor/github.com/bazelbuild/bazel-gazelle/rule:go_default_library"], ) - -filegroup( - name = "all_files", - testonly = True, - srcs = [ - "BUILD.bazel", - "fix.go", - "merger.go", - "merger_test.go", - ], - visibility = ["//visibility:public"], -) diff --git a/vendor/github.com/bazelbuild/bazel-gazelle/pathtools/BUILD.bazel b/vendor/github.com/bazelbuild/bazel-gazelle/pathtools/BUILD.bazel index ab19056bc0..bd33bae8f8 100644 --- a/vendor/github.com/bazelbuild/bazel-gazelle/pathtools/BUILD.bazel +++ b/vendor/github.com/bazelbuild/bazel-gazelle/pathtools/BUILD.bazel @@ -7,14 +7,3 @@ go_library( importpath = "github.com/bazelbuild/bazel-gazelle/pathtools", visibility = ["//visibility:public"], ) - -filegroup( - name = "all_files", - testonly = True, - srcs = [ - "BUILD.bazel", - "path.go", - "path_test.go", - ], - visibility = ["//visibility:public"], -) diff --git a/vendor/github.com/bazelbuild/bazel-gazelle/repo/BUILD.bazel b/vendor/github.com/bazelbuild/bazel-gazelle/repo/BUILD.bazel index 653a7975df..c2eeda6727 100644 --- a/vendor/github.com/bazelbuild/bazel-gazelle/repo/BUILD.bazel +++ b/vendor/github.com/bazelbuild/bazel-gazelle/repo/BUILD.bazel @@ -16,17 +16,3 @@ go_library( "//vendor/golang.org/x/tools/go/vcs:go_default_library", ], ) - -filegroup( - name = "all_files", - testonly = True, - srcs = [ - "BUILD.bazel", - "remote.go", - "remote_test.go", - "repo.go", - "repo_test.go", - "stubs_test.go", - ], - visibility = ["//visibility:public"], -) diff --git a/vendor/github.com/bazelbuild/bazel-gazelle/resolve/BUILD.bazel b/vendor/github.com/bazelbuild/bazel-gazelle/resolve/BUILD.bazel index f7af28493f..fa81e50199 100644 --- a/vendor/github.com/bazelbuild/bazel-gazelle/resolve/BUILD.bazel +++ b/vendor/github.com/bazelbuild/bazel-gazelle/resolve/BUILD.bazel @@ -16,14 +16,3 @@ go_library( "//vendor/github.com/bazelbuild/bazel-gazelle/rule:go_default_library", ], ) - -filegroup( - name = "all_files", - testonly = True, - srcs = [ - "BUILD.bazel", - "config.go", - "index.go", - ], - visibility = ["//visibility:public"], -) diff --git a/vendor/github.com/bazelbuild/bazel-gazelle/rule/BUILD.bazel b/vendor/github.com/bazelbuild/bazel-gazelle/rule/BUILD.bazel index 4491dc26a0..2cca145331 100644 --- a/vendor/github.com/bazelbuild/bazel-gazelle/rule/BUILD.bazel +++ b/vendor/github.com/bazelbuild/bazel-gazelle/rule/BUILD.bazel @@ -22,23 +22,3 @@ go_library( "//vendor/github.com/bazelbuild/buildtools/tables:go_default_library", ], ) - -filegroup( - name = "all_files", - testonly = True, - srcs = [ - "BUILD.bazel", - "directives.go", - "directives_test.go", - "expr.go", - "merge.go", - "platform.go", - "platform_strings.go", - "rule.go", - "rule_test.go", - "sort_labels.go", - "types.go", - "value.go", - ], - visibility = ["//visibility:public"], -) diff --git a/vendor/github.com/bazelbuild/bazel-gazelle/walk/BUILD.bazel b/vendor/github.com/bazelbuild/bazel-gazelle/walk/BUILD.bazel index c1a38381b6..983dbd811b 100644 --- a/vendor/github.com/bazelbuild/bazel-gazelle/walk/BUILD.bazel +++ b/vendor/github.com/bazelbuild/bazel-gazelle/walk/BUILD.bazel @@ -16,15 +16,3 @@ go_library( "//vendor/github.com/bazelbuild/bazel-gazelle/rule:go_default_library", ], ) - -filegroup( - name = "all_files", - testonly = True, - srcs = [ - "BUILD.bazel", - "config.go", - "walk.go", - "walk_test.go", - ], - visibility = ["//visibility:public"], -) diff --git a/vendor/github.com/bazelbuild/buildtools/build/BUILD.bazel b/vendor/github.com/bazelbuild/buildtools/build/BUILD.bazel index 5b81ce7119..4b5b5f195b 100644 --- a/vendor/github.com/bazelbuild/buildtools/build/BUILD.bazel +++ b/vendor/github.com/bazelbuild/buildtools/build/BUILD.bazel @@ -1,17 +1,10 @@ -# gazelle:exclude parse.y.go load("@io_bazel_rules_go//go:def.bzl", "go_library") -load(":build_defs.bzl", "go_yacc") - -go_yacc( - src = "parse.y", - out = "parse.y.baz.go", -) go_library( name = "go_default_library", srcs = [ "lex.go", - "parse.y.baz.go", # keep + "parse.y.go", "print.go", "quote.go", "rewrite.go", diff --git a/vendor/k8s.io/kubectl/pkg/drain/BUILD.bazel b/vendor/k8s.io/kubectl/pkg/drain/BUILD.bazel new file mode 100644 index 0000000000..38fb0746b6 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/drain/BUILD.bazel @@ -0,0 +1,31 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "cordon.go", + "default.go", + "drain.go", + "filters.go", + ], + importmap = "k8s.io/kops/vendor/k8s.io/kubectl/pkg/drain", + importpath = "k8s.io/kubectl/pkg/drain", + visibility = ["//visibility:public"], + deps = [ + "//vendor/k8s.io/api/apps/v1:go_default_library", + "//vendor/k8s.io/api/core/v1:go_default_library", + "//vendor/k8s.io/api/policy/v1beta1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/fields:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/labels:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/types:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/util/json:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library", + "//vendor/k8s.io/client-go/kubernetes:go_default_library", + ], +) diff --git a/vendor/k8s.io/kubectl/pkg/drain/cordon.go b/vendor/k8s.io/kubectl/pkg/drain/cordon.go new file mode 100644 index 0000000000..fc33975266 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/drain/cordon.go @@ -0,0 +1,97 @@ +/* +Copyright 2019 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 drain + +import ( + "fmt" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/json" + "k8s.io/apimachinery/pkg/util/strategicpatch" + "k8s.io/client-go/kubernetes" +) + +// CordonHelper wraps functionality to cordon/uncordon nodes +type CordonHelper struct { + node *corev1.Node + desired bool +} + +// NewCordonHelper returns a new CordonHelper +func NewCordonHelper(node *corev1.Node) *CordonHelper { + return &CordonHelper{ + node: node, + } +} + +// NewCordonHelperFromRuntimeObject returns a new CordonHelper, or an error if given object is not a +// node or cannot be encoded as JSON +func NewCordonHelperFromRuntimeObject(nodeObject runtime.Object, scheme *runtime.Scheme, gvk schema.GroupVersionKind) (*CordonHelper, error) { + nodeObject, err := scheme.ConvertToVersion(nodeObject, gvk.GroupVersion()) + if err != nil { + return nil, err + } + + node, ok := nodeObject.(*corev1.Node) + if !ok { + return nil, fmt.Errorf("unexpected type %T", nodeObject) + } + + return NewCordonHelper(node), nil +} + +// UpdateIfRequired returns true if c.node.Spec.Unschedulable isn't already set, +// or false when no change is needed +func (c *CordonHelper) UpdateIfRequired(desired bool) bool { + c.desired = desired + if c.node.Spec.Unschedulable == c.desired { + return false + } + return true +} + +// PatchOrReplace uses given clientset to update the node status, either by patching or +// updating the given node object; it may return error if the object cannot be encoded as +// JSON, or if either patch or update calls fail; it will also return a second error +// whenever creating a patch has failed +func (c *CordonHelper) PatchOrReplace(clientset kubernetes.Interface) (error, error) { + client := clientset.CoreV1().Nodes() + + oldData, err := json.Marshal(c.node) + if err != nil { + return err, nil + } + + c.node.Spec.Unschedulable = c.desired + + newData, err := json.Marshal(c.node) + if err != nil { + return err, nil + } + + patchBytes, patchErr := strategicpatch.CreateTwoWayMergePatch(oldData, newData, c.node) + if patchErr == nil { + _, err = client.Patch(c.node.Name, types.StrategicMergePatchType, patchBytes) + } else { + _, err = client.Update(c.node) + } + return err, patchErr +} diff --git a/vendor/k8s.io/kubectl/pkg/drain/default.go b/vendor/k8s.io/kubectl/pkg/drain/default.go new file mode 100644 index 0000000000..ec0351b0ff --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/drain/default.go @@ -0,0 +1,69 @@ +/* +Copyright 2019 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 drain + +import ( + "fmt" + + corev1 "k8s.io/api/core/v1" + utilerrors "k8s.io/apimachinery/pkg/util/errors" +) + +// This file contains default implementations of how to +// drain/cordon/uncordon nodes. These functions may be called +// directly, or their functionality copied into your own code, for +// example if you want different output behaviour. + +// RunNodeDrain shows the canonical way to drain a node. +// You should first cordon the node, e.g. using RunCordonOrUncordon +func RunNodeDrain(drainer *Helper, nodeName string) error { + // TODO(justinsb): Ensure we have adequate e2e coverage of this function in library consumers + list, errs := drainer.GetPodsForDeletion(nodeName) + if errs != nil { + return utilerrors.NewAggregate(errs) + } + if warnings := list.Warnings(); warnings != "" { + fmt.Fprintf(drainer.ErrOut, "WARNING: %s\n", warnings) + } + + if err := drainer.DeleteOrEvictPods(list.Pods()); err != nil { + // Maybe warn about non-deleted pods here + return err + } + return nil +} + +// RunCordonOrUncordon demonstrates the canonical way to cordon or uncordon a Node +func RunCordonOrUncordon(drainer *Helper, node *corev1.Node, desired bool) error { + // TODO(justinsb): Ensure we have adequate e2e coverage of this function in library consumers + c := NewCordonHelper(node) + + if updateRequired := c.UpdateIfRequired(desired); !updateRequired { + // Already done + return nil + } + + err, patchErr := c.PatchOrReplace(drainer.Client) + if patchErr != nil { + return patchErr + } + if err != nil { + return err + } + + return nil +} diff --git a/vendor/k8s.io/kubectl/pkg/drain/drain.go b/vendor/k8s.io/kubectl/pkg/drain/drain.go new file mode 100644 index 0000000000..2e9c9e8c49 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/drain/drain.go @@ -0,0 +1,292 @@ +/* +Copyright 2019 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 drain + +import ( + "fmt" + "io" + "math" + "time" + + corev1 "k8s.io/api/core/v1" + policyv1beta1 "k8s.io/api/policy/v1beta1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/kubernetes" +) + +const ( + // EvictionKind represents the kind of evictions object + EvictionKind = "Eviction" + // EvictionSubresource represents the kind of evictions object as pod's subresource + EvictionSubresource = "pods/eviction" +) + +// Helper contains the parameters to control the behaviour of drainer +type Helper struct { + Client kubernetes.Interface + Force bool + GracePeriodSeconds int + IgnoreAllDaemonSets bool + Timeout time.Duration + DeleteLocalData bool + Selector string + PodSelector string + Out io.Writer + ErrOut io.Writer + + // TODO(justinsb): unnecessary? + DryRun bool + + // OnPodDeletedOrEvicted is called when a pod is evicted/deleted; for printing progress output + OnPodDeletedOrEvicted func(pod *corev1.Pod, usingEviction bool) +} + +// CheckEvictionSupport uses Discovery API to find out if the server support +// eviction subresource If support, it will return its groupVersion; Otherwise, +// it will return an empty string +func CheckEvictionSupport(clientset kubernetes.Interface) (string, error) { + discoveryClient := clientset.Discovery() + groupList, err := discoveryClient.ServerGroups() + if err != nil { + return "", err + } + foundPolicyGroup := false + var policyGroupVersion string + for _, group := range groupList.Groups { + if group.Name == "policy" { + foundPolicyGroup = true + policyGroupVersion = group.PreferredVersion.GroupVersion + break + } + } + if !foundPolicyGroup { + return "", nil + } + resourceList, err := discoveryClient.ServerResourcesForGroupVersion("v1") + if err != nil { + return "", err + } + for _, resource := range resourceList.APIResources { + if resource.Name == EvictionSubresource && resource.Kind == EvictionKind { + return policyGroupVersion, nil + } + } + return "", nil +} + +func (d *Helper) makeDeleteOptions() *metav1.DeleteOptions { + deleteOptions := &metav1.DeleteOptions{} + if d.GracePeriodSeconds >= 0 { + gracePeriodSeconds := int64(d.GracePeriodSeconds) + deleteOptions.GracePeriodSeconds = &gracePeriodSeconds + } + return deleteOptions +} + +// DeletePod will delete the given pod, or return an error if it couldn't +func (d *Helper) DeletePod(pod corev1.Pod) error { + return d.Client.CoreV1().Pods(pod.Namespace).Delete(pod.Name, d.makeDeleteOptions()) +} + +// EvictPod will evict the give pod, or return an error if it couldn't +func (d *Helper) EvictPod(pod corev1.Pod, policyGroupVersion string) error { + eviction := &policyv1beta1.Eviction{ + TypeMeta: metav1.TypeMeta{ + APIVersion: policyGroupVersion, + Kind: EvictionKind, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: pod.Name, + Namespace: pod.Namespace, + }, + DeleteOptions: d.makeDeleteOptions(), + } + // Remember to change change the URL manipulation func when Eviction's version change + return d.Client.PolicyV1beta1().Evictions(eviction.Namespace).Evict(eviction) +} + +// GetPodsForDeletion receives resource info for a node, and returns those pods as PodDeleteList, +// or error if it cannot list pods. All pods that are ready to be deleted can be obtained with .Pods(), +// and string with all warning can be obtained with .Warnings(), and .Errors() for all errors that +// occurred during deletion. +func (d *Helper) GetPodsForDeletion(nodeName string) (*podDeleteList, []error) { + labelSelector, err := labels.Parse(d.PodSelector) + if err != nil { + return nil, []error{err} + } + + podList, err := d.Client.CoreV1().Pods(metav1.NamespaceAll).List(metav1.ListOptions{ + LabelSelector: labelSelector.String(), + FieldSelector: fields.SelectorFromSet(fields.Set{"spec.nodeName": nodeName}).String()}) + if err != nil { + return nil, []error{err} + } + + pods := []podDelete{} + + for _, pod := range podList.Items { + var status podDeleteStatus + for _, filter := range d.makeFilters() { + status = filter(pod) + if !status.delete { + // short-circuit as soon as pod is filtered out + // at that point, there is no reason to run pod + // through any additional filters + break + } + } + pods = append(pods, podDelete{ + pod: pod, + status: status, + }) + } + + list := &podDeleteList{items: pods} + + if errs := list.errors(); len(errs) > 0 { + return list, errs + } + + return list, nil +} + +// DeleteOrEvictPods deletes or evicts the pods on the api server +func (d *Helper) DeleteOrEvictPods(pods []corev1.Pod) error { + if len(pods) == 0 { + return nil + } + + policyGroupVersion, err := CheckEvictionSupport(d.Client) + if err != nil { + return err + } + + // TODO(justinsb): unnecessary? + getPodFn := func(namespace, name string) (*corev1.Pod, error) { + return d.Client.CoreV1().Pods(namespace).Get(name, metav1.GetOptions{}) + } + + if len(policyGroupVersion) > 0 { + return d.evictPods(pods, policyGroupVersion, getPodFn) + } + + return d.deletePods(pods, getPodFn) +} + +func (d *Helper) evictPods(pods []corev1.Pod, policyGroupVersion string, getPodFn func(namespace, name string) (*corev1.Pod, error)) error { + returnCh := make(chan error, 1) + + for _, pod := range pods { + go func(pod corev1.Pod, returnCh chan error) { + for { + fmt.Fprintf(d.Out, "evicting pod %q\n", pod.Name) + err := d.EvictPod(pod, policyGroupVersion) + if err == nil { + break + } else if apierrors.IsNotFound(err) { + returnCh <- nil + return + } else if apierrors.IsTooManyRequests(err) { + fmt.Fprintf(d.ErrOut, "error when evicting pod %q (will retry after 5s): %v\n", pod.Name, err) + time.Sleep(5 * time.Second) + } else { + returnCh <- fmt.Errorf("error when evicting pod %q: %v", pod.Name, err) + return + } + } + _, err := waitForDelete([]corev1.Pod{pod}, 1*time.Second, time.Duration(math.MaxInt64), true, getPodFn, d.OnPodDeletedOrEvicted) + if err == nil { + returnCh <- nil + } else { + returnCh <- fmt.Errorf("error when waiting for pod %q terminating: %v", pod.Name, err) + } + }(pod, returnCh) + } + + doneCount := 0 + var errors []error + + // 0 timeout means infinite, we use MaxInt64 to represent it. + var globalTimeout time.Duration + if d.Timeout == 0 { + globalTimeout = time.Duration(math.MaxInt64) + } else { + globalTimeout = d.Timeout + } + globalTimeoutCh := time.After(globalTimeout) + numPods := len(pods) + for doneCount < numPods { + select { + case err := <-returnCh: + doneCount++ + if err != nil { + errors = append(errors, err) + } + case <-globalTimeoutCh: + return fmt.Errorf("drain did not complete within %v", globalTimeout) + } + } + return utilerrors.NewAggregate(errors) +} + +func (d *Helper) deletePods(pods []corev1.Pod, getPodFn func(namespace, name string) (*corev1.Pod, error)) error { + // 0 timeout means infinite, we use MaxInt64 to represent it. + var globalTimeout time.Duration + if d.Timeout == 0 { + globalTimeout = time.Duration(math.MaxInt64) + } else { + globalTimeout = d.Timeout + } + for _, pod := range pods { + err := d.DeletePod(pod) + if err != nil && !apierrors.IsNotFound(err) { + return err + } + } + _, err := waitForDelete(pods, 1*time.Second, globalTimeout, false, getPodFn, d.OnPodDeletedOrEvicted) + return err +} + +func waitForDelete(pods []corev1.Pod, interval, timeout time.Duration, usingEviction bool, getPodFn func(string, string) (*corev1.Pod, error), onDoneFn func(pod *corev1.Pod, usingEviction bool)) ([]corev1.Pod, error) { + err := wait.PollImmediate(interval, timeout, func() (bool, error) { + pendingPods := []corev1.Pod{} + for i, pod := range pods { + p, err := getPodFn(pod.Namespace, pod.Name) + if apierrors.IsNotFound(err) || (p != nil && p.ObjectMeta.UID != pod.ObjectMeta.UID) { + if onDoneFn != nil { + onDoneFn(&pod, usingEviction) + } + continue + } else if err != nil { + return false, err + } else { + pendingPods = append(pendingPods, pods[i]) + } + } + pods = pendingPods + if len(pendingPods) > 0 { + return false, nil + } + return true, nil + }) + return pods, err +} diff --git a/vendor/k8s.io/kubectl/pkg/drain/filters.go b/vendor/k8s.io/kubectl/pkg/drain/filters.go new file mode 100644 index 0000000000..2cbba24563 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/drain/filters.go @@ -0,0 +1,223 @@ +/* +Copyright 2019 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 drain + +import ( + "fmt" + "strings" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + daemonSetFatal = "DaemonSet-managed Pods (use --ignore-daemonsets to ignore)" + daemonSetWarning = "ignoring DaemonSet-managed Pods" + localStorageFatal = "Pods with local storage (use --delete-local-data to override)" + localStorageWarning = "deleting Pods with local storage" + unmanagedFatal = "Pods not managed by ReplicationController, ReplicaSet, Job, DaemonSet or StatefulSet (use --force to override)" + unmanagedWarning = "deleting Pods not managed by ReplicationController, ReplicaSet, Job, DaemonSet or StatefulSet" +) + +type podDelete struct { + pod corev1.Pod + status podDeleteStatus +} + +type podDeleteList struct { + items []podDelete +} + +func (l *podDeleteList) Pods() []corev1.Pod { + pods := []corev1.Pod{} + for _, i := range l.items { + if i.status.delete { + pods = append(pods, i.pod) + } + } + return pods +} + +func (l *podDeleteList) Warnings() string { + ps := make(map[string][]string) + for _, i := range l.items { + if i.status.reason == podDeleteStatusTypeWarning { + ps[i.status.message] = append(ps[i.status.message], fmt.Sprintf("%s/%s", i.pod.Namespace, i.pod.Name)) + } + } + + msgs := []string{} + for key, pods := range ps { + msgs = append(msgs, fmt.Sprintf("%s: %s", key, strings.Join(pods, ", "))) + } + return strings.Join(msgs, "; ") +} + +func (l *podDeleteList) errors() []error { + failedPods := make(map[string][]string) + for _, i := range l.items { + if i.status.reason == podDeleteStatusTypeError { + msg := i.status.message + if msg == "" { + msg = "unexpected error" + } + failedPods[msg] = append(failedPods[msg], fmt.Sprintf("%s/%s", i.pod.Namespace, i.pod.Name)) + } + } + errs := make([]error, 0) + for msg, pods := range failedPods { + errs = append(errs, fmt.Errorf("cannot delete %s: %s", msg, strings.Join(pods, ", "))) + } + return errs +} + +type podDeleteStatus struct { + delete bool + reason string + message string +} + +// Takes a pod and returns a PodDeleteStatus +type podFilter func(corev1.Pod) podDeleteStatus + +const ( + podDeleteStatusTypeOkay = "Okay" + podDeleteStatusTypeSkip = "Skip" + podDeleteStatusTypeWarning = "Warning" + podDeleteStatusTypeError = "Error" +) + +func makePodDeleteStatusOkay() podDeleteStatus { + return podDeleteStatus{ + delete: true, + reason: podDeleteStatusTypeOkay, + } +} + +func makePodDeleteStatusSkip() podDeleteStatus { + return podDeleteStatus{ + delete: false, + reason: podDeleteStatusTypeSkip, + } +} + +func makePodDeleteStatusWithWarning(delete bool, message string) podDeleteStatus { + return podDeleteStatus{ + delete: delete, + reason: podDeleteStatusTypeWarning, + message: message, + } +} + +func makePodDeleteStatusWithError(message string) podDeleteStatus { + return podDeleteStatus{ + delete: false, + reason: podDeleteStatusTypeError, + message: message, + } +} + +func (d *Helper) makeFilters() []podFilter { + return []podFilter{ + d.daemonSetFilter, + d.mirrorPodFilter, + d.localStorageFilter, + d.unreplicatedFilter, + } +} + +func hasLocalStorage(pod corev1.Pod) bool { + for _, volume := range pod.Spec.Volumes { + if volume.EmptyDir != nil { + return true + } + } + + return false +} + +func (d *Helper) daemonSetFilter(pod corev1.Pod) podDeleteStatus { + // Note that we return false in cases where the pod is DaemonSet managed, + // regardless of flags. + // + // The exception is for pods that are orphaned (the referencing + // management resource - including DaemonSet - is not found). + // Such pods will be deleted if --force is used. + controllerRef := metav1.GetControllerOf(&pod) + if controllerRef == nil || controllerRef.Kind != appsv1.SchemeGroupVersion.WithKind("DaemonSet").Kind { + return makePodDeleteStatusOkay() + } + // Any finished pod can be removed. + if pod.Status.Phase == corev1.PodSucceeded || pod.Status.Phase == corev1.PodFailed { + return makePodDeleteStatusOkay() + } + + if _, err := d.Client.AppsV1().DaemonSets(pod.Namespace).Get(controllerRef.Name, metav1.GetOptions{}); err != nil { + // remove orphaned pods with a warning if --force is used + if apierrors.IsNotFound(err) && d.Force { + return makePodDeleteStatusWithWarning(true, err.Error()) + } + + return makePodDeleteStatusWithError(err.Error()) + } + + if !d.IgnoreAllDaemonSets { + return makePodDeleteStatusWithError(daemonSetFatal) + } + + return makePodDeleteStatusWithWarning(false, daemonSetWarning) +} + +func (d *Helper) mirrorPodFilter(pod corev1.Pod) podDeleteStatus { + if _, found := pod.ObjectMeta.Annotations[corev1.MirrorPodAnnotationKey]; found { + return makePodDeleteStatusSkip() + } + return makePodDeleteStatusOkay() +} + +func (d *Helper) localStorageFilter(pod corev1.Pod) podDeleteStatus { + if !hasLocalStorage(pod) { + return makePodDeleteStatusOkay() + } + // Any finished pod can be removed. + if pod.Status.Phase == corev1.PodSucceeded || pod.Status.Phase == corev1.PodFailed { + return makePodDeleteStatusOkay() + } + if !d.DeleteLocalData { + return makePodDeleteStatusWithError(localStorageFatal) + } + + return makePodDeleteStatusWithWarning(true, localStorageWarning) +} + +func (d *Helper) unreplicatedFilter(pod corev1.Pod) podDeleteStatus { + // any finished pod can be removed + if pod.Status.Phase == corev1.PodSucceeded || pod.Status.Phase == corev1.PodFailed { + return makePodDeleteStatusOkay() + } + + controllerRef := metav1.GetControllerOf(&pod) + if controllerRef != nil { + return makePodDeleteStatusOkay() + } + if d.Force { + return makePodDeleteStatusWithWarning(true, unmanagedWarning) + } + return makePodDeleteStatusWithError(unmanagedFatal) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 2f5c3571cd..8ba4e7b6a3 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1035,6 +1035,7 @@ k8s.io/kube-openapi/pkg/util/proto/validation k8s.io/kubectl/pkg/cmd/util k8s.io/kubectl/pkg/cmd/util/editor k8s.io/kubectl/pkg/cmd/util/editor/crlf +k8s.io/kubectl/pkg/drain k8s.io/kubectl/pkg/generated k8s.io/kubectl/pkg/scheme k8s.io/kubectl/pkg/util